├── .editorconfig ├── .gitignore ├── README.md ├── index.html ├── package-lock.json ├── package.json ├── public ├── Group 3.svg ├── collections │ ├── Jesperish1.jpg │ ├── Jesperish2.jpg │ ├── cherifkid1.jpg │ ├── cherifkid2.png │ ├── jardel1.jpg │ ├── jardel2.jpg │ ├── noise1.png │ ├── noise2.png │ ├── raegular1.jpg │ ├── raegular2.jpg │ ├── travis1.png │ ├── travis2.png │ ├── wrath1.png │ └── wrath2.png ├── contact │ ├── contact_1.png │ ├── contact_2.png │ └── contact_3.png ├── detail-minified │ ├── d1_1.png │ ├── d1_2.png │ ├── d1_3.png │ ├── d1_4.png │ ├── d2_1.png │ ├── d2_2.png │ ├── d2_3.png │ ├── d2_4.png │ ├── d2_5.png │ ├── d2_6.png │ ├── d3_1.png │ ├── d3_2.png │ ├── d3_3.png │ ├── d3_4.png │ ├── d3_5.png │ ├── d3_6.png │ ├── d4_1.png │ ├── d4_2.png │ ├── d4_3.png │ ├── d4_4.png │ ├── d4_5.png │ ├── d4_6.png │ ├── d4_7.jpg │ ├── d5_1.png │ ├── d5_2.png │ ├── d5_3.png │ ├── d5_4.png │ ├── d5_5.png │ ├── d5_6.png │ ├── d5_7.png │ ├── d6_1.png │ ├── d6_2.jpg │ ├── d6_3.jpg │ ├── d6_4.jpg │ ├── d6_5.jpg │ ├── d6_6.jpg │ ├── d7_1.webp │ ├── d7_2.webp │ ├── d7_3.webp │ ├── d7_4.webp │ ├── d7_5.webp │ └── d7_6.webp ├── detail │ ├── d1_1.png │ ├── d1_2.png │ ├── d1_3.png │ ├── d1_4.png │ ├── d2_1.png │ ├── d2_2.png │ ├── d2_3.png │ ├── d2_4.png │ ├── d2_5.png │ ├── d2_6.png │ ├── d3_1.png │ ├── d3_2.png │ ├── d3_3.png │ ├── d3_4.png │ ├── d3_5.png │ ├── d3_6.png │ ├── d4_1.png │ ├── d4_2.png │ ├── d4_3.png │ ├── d4_4.png │ ├── d4_5.png │ ├── d4_6.png │ ├── d4_7.jpg │ ├── d5_1.png │ ├── d5_2.png │ ├── d5_3.png │ ├── d5_4.png │ ├── d5_5.png │ ├── d5_6.png │ ├── d5_7.png │ ├── d6_1.png │ ├── d6_2.jpg │ ├── d6_3.jpg │ ├── d6_4.jpg │ ├── d6_5.jpg │ ├── d6_6.jpg │ ├── d7_1.webp │ ├── d7_2.webp │ ├── d7_3.webp │ ├── d7_4.webp │ ├── d7_5.webp │ └── d7_6.webp ├── favicons │ ├── android-chrome-192x192.png │ ├── android-chrome-512x512.png │ ├── apple-touch-icon.png │ ├── browserconfig.xml │ ├── favicon-16x16.png │ ├── favicon-32x32.png │ ├── favicon.ico │ └── mstile-150x150.png ├── fonts │ ├── LeagueSpartan-Bold.ttf │ ├── LeagueSpartan-ExtraLight.ttf │ └── LeagueSpartan-Regular.ttf └── home │ ├── home1.jpg │ ├── home2.jpg │ ├── home3.jpg │ └── home4.jpg ├── site.webmanifest ├── src ├── Canvas │ ├── Collections │ │ ├── BasicVer.glsl │ │ ├── BufferFrag.glsl │ │ ├── LastFrag.glsl │ │ ├── Media.js │ │ ├── collectionsCanvas.js │ │ ├── fragment.glsl │ │ └── vertex.glsl │ ├── Contact │ │ ├── contactCanvas.js │ │ ├── fragment.glsl │ │ └── vertex.glsl │ ├── Demo │ │ ├── demoCanvas.js │ │ ├── fragment.glsl │ │ └── vertex.glsl │ ├── Home │ │ ├── fragment.glsl │ │ ├── homeCanvas.js │ │ └── vertex.glsl │ ├── Preloader │ │ └── preloaderCanvas.js │ └── canvas.js ├── Pages │ ├── Collections │ │ ├── collections.html │ │ ├── collections.js │ │ └── collections.scss │ ├── Contact │ │ ├── contact.html │ │ ├── contact.js │ │ └── contact.scss │ ├── Demo │ │ ├── demo.html │ │ ├── demo.js │ │ └── demo.scss │ ├── Details │ │ ├── detail.html │ │ ├── detail.js │ │ └── detail.scss │ ├── Home │ │ ├── home.html │ │ ├── home.js │ │ └── home.scss │ ├── Preloader │ │ ├── preloader.html │ │ ├── preloader.js │ │ └── preloader.scss │ └── page.scss ├── animation │ ├── TransitionCollectionsHome.js │ ├── TransitionContactHome.js │ ├── TransitionDemoHome.js │ ├── TransitionDetailCollections.js │ ├── TransitionHomeCollections.js │ ├── TransitionHomeContact.js │ ├── TransitionPreloaderDemo.js │ ├── collectionsAnimation.js │ ├── collectionsAnimationService.js │ ├── collectionsNav.js │ ├── collectionsNext.js │ ├── collectionsPrevious.js │ ├── collectionsTooltipBack.js │ ├── contactAnimation.js │ ├── demoComplete.js │ ├── demoTooltipAnimation.js │ ├── homeFixation.js │ ├── homeFixationInit.js │ ├── homeToCollections.js │ ├── homeToContact.js │ ├── homeTooltipCollections.js │ ├── homeTooltipContact.js │ ├── shaders │ │ ├── BasicFrag.glsl │ │ ├── BasicVer.glsl │ │ └── WhiteFrag.glsl │ └── transitionFallBack.js ├── app.js ├── classes │ ├── Component.js │ ├── Page.js │ ├── Router.js │ └── Timer.js ├── components │ ├── components.scss │ ├── gridFixation │ │ ├── gridFixation.html │ │ ├── gridFixation.js │ │ └── gridFixation.scss │ └── ressortButton │ │ ├── ressortButton.html │ │ ├── ressortButton.js │ │ └── ressortButton.scss ├── styles │ ├── base │ │ ├── base.scss │ │ ├── fonts.scss │ │ └── reset.scss │ ├── index.scss │ └── utils │ │ ├── mixins.scss │ │ ├── responsive.scss │ │ └── variables.scss └── utils │ ├── namhai.js │ ├── text.js │ └── utilsText.js └── vercel.json /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | indent_size = 2 7 | indent_style = space 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | 26 | .vercel 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### PORTFOLIO 2 | 3 | https://namhai.vercel.app 4 | 5 | ![Portfolio](https://user-images.githubusercontent.com/76962312/191399207-9ea906b4-3fea-43ea-8368-043f37090edb.png) 6 | 7 | ## Stack 8 | 9 | - [Vite](https://vitejs.dev) : Build tool 10 | - Frameworkless 11 | - [OGL](https://oframe.github.io/ogl/examples/?src=point-lighting.html) : less boilerplate for WebGL 12 | - [Vercel](vercel.com/) : Deployment 13 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Nam Hai 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 |
24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "portfolio-1", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "vite build", 9 | "preview": "vite preview" 10 | }, 11 | "devDependencies": { 12 | "vite": "^3.0.7" 13 | }, 14 | "dependencies": { 15 | "ogl": "^0.0.97", 16 | "sass": "^1.54.5" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /public/Group 3.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /public/collections/Jesperish1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/collections/Jesperish1.jpg -------------------------------------------------------------------------------- /public/collections/Jesperish2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/collections/Jesperish2.jpg -------------------------------------------------------------------------------- /public/collections/cherifkid1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/collections/cherifkid1.jpg -------------------------------------------------------------------------------- /public/collections/cherifkid2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/collections/cherifkid2.png -------------------------------------------------------------------------------- /public/collections/jardel1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/collections/jardel1.jpg -------------------------------------------------------------------------------- /public/collections/jardel2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/collections/jardel2.jpg -------------------------------------------------------------------------------- /public/collections/noise1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/collections/noise1.png -------------------------------------------------------------------------------- /public/collections/noise2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/collections/noise2.png -------------------------------------------------------------------------------- /public/collections/raegular1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/collections/raegular1.jpg -------------------------------------------------------------------------------- /public/collections/raegular2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/collections/raegular2.jpg -------------------------------------------------------------------------------- /public/collections/travis1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/collections/travis1.png -------------------------------------------------------------------------------- /public/collections/travis2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/collections/travis2.png -------------------------------------------------------------------------------- /public/collections/wrath1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/collections/wrath1.png -------------------------------------------------------------------------------- /public/collections/wrath2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/collections/wrath2.png -------------------------------------------------------------------------------- /public/contact/contact_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/contact/contact_1.png -------------------------------------------------------------------------------- /public/contact/contact_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/contact/contact_2.png -------------------------------------------------------------------------------- /public/contact/contact_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/contact/contact_3.png -------------------------------------------------------------------------------- /public/detail-minified/d1_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail-minified/d1_1.png -------------------------------------------------------------------------------- /public/detail-minified/d1_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail-minified/d1_2.png -------------------------------------------------------------------------------- /public/detail-minified/d1_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail-minified/d1_3.png -------------------------------------------------------------------------------- /public/detail-minified/d1_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail-minified/d1_4.png -------------------------------------------------------------------------------- /public/detail-minified/d2_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail-minified/d2_1.png -------------------------------------------------------------------------------- /public/detail-minified/d2_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail-minified/d2_2.png -------------------------------------------------------------------------------- /public/detail-minified/d2_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail-minified/d2_3.png -------------------------------------------------------------------------------- /public/detail-minified/d2_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail-minified/d2_4.png -------------------------------------------------------------------------------- /public/detail-minified/d2_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail-minified/d2_5.png -------------------------------------------------------------------------------- /public/detail-minified/d2_6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail-minified/d2_6.png -------------------------------------------------------------------------------- /public/detail-minified/d3_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail-minified/d3_1.png -------------------------------------------------------------------------------- /public/detail-minified/d3_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail-minified/d3_2.png -------------------------------------------------------------------------------- /public/detail-minified/d3_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail-minified/d3_3.png -------------------------------------------------------------------------------- /public/detail-minified/d3_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail-minified/d3_4.png -------------------------------------------------------------------------------- /public/detail-minified/d3_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail-minified/d3_5.png -------------------------------------------------------------------------------- /public/detail-minified/d3_6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail-minified/d3_6.png -------------------------------------------------------------------------------- /public/detail-minified/d4_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail-minified/d4_1.png -------------------------------------------------------------------------------- /public/detail-minified/d4_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail-minified/d4_2.png -------------------------------------------------------------------------------- /public/detail-minified/d4_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail-minified/d4_3.png -------------------------------------------------------------------------------- /public/detail-minified/d4_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail-minified/d4_4.png -------------------------------------------------------------------------------- /public/detail-minified/d4_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail-minified/d4_5.png -------------------------------------------------------------------------------- /public/detail-minified/d4_6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail-minified/d4_6.png -------------------------------------------------------------------------------- /public/detail-minified/d4_7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail-minified/d4_7.jpg -------------------------------------------------------------------------------- /public/detail-minified/d5_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail-minified/d5_1.png -------------------------------------------------------------------------------- /public/detail-minified/d5_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail-minified/d5_2.png -------------------------------------------------------------------------------- /public/detail-minified/d5_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail-minified/d5_3.png -------------------------------------------------------------------------------- /public/detail-minified/d5_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail-minified/d5_4.png -------------------------------------------------------------------------------- /public/detail-minified/d5_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail-minified/d5_5.png -------------------------------------------------------------------------------- /public/detail-minified/d5_6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail-minified/d5_6.png -------------------------------------------------------------------------------- /public/detail-minified/d5_7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail-minified/d5_7.png -------------------------------------------------------------------------------- /public/detail-minified/d6_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail-minified/d6_1.png -------------------------------------------------------------------------------- /public/detail-minified/d6_2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail-minified/d6_2.jpg -------------------------------------------------------------------------------- /public/detail-minified/d6_3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail-minified/d6_3.jpg -------------------------------------------------------------------------------- /public/detail-minified/d6_4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail-minified/d6_4.jpg -------------------------------------------------------------------------------- /public/detail-minified/d6_5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail-minified/d6_5.jpg -------------------------------------------------------------------------------- /public/detail-minified/d6_6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail-minified/d6_6.jpg -------------------------------------------------------------------------------- /public/detail-minified/d7_1.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail-minified/d7_1.webp -------------------------------------------------------------------------------- /public/detail-minified/d7_2.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail-minified/d7_2.webp -------------------------------------------------------------------------------- /public/detail-minified/d7_3.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail-minified/d7_3.webp -------------------------------------------------------------------------------- /public/detail-minified/d7_4.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail-minified/d7_4.webp -------------------------------------------------------------------------------- /public/detail-minified/d7_5.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail-minified/d7_5.webp -------------------------------------------------------------------------------- /public/detail-minified/d7_6.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail-minified/d7_6.webp -------------------------------------------------------------------------------- /public/detail/d1_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail/d1_1.png -------------------------------------------------------------------------------- /public/detail/d1_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail/d1_2.png -------------------------------------------------------------------------------- /public/detail/d1_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail/d1_3.png -------------------------------------------------------------------------------- /public/detail/d1_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail/d1_4.png -------------------------------------------------------------------------------- /public/detail/d2_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail/d2_1.png -------------------------------------------------------------------------------- /public/detail/d2_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail/d2_2.png -------------------------------------------------------------------------------- /public/detail/d2_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail/d2_3.png -------------------------------------------------------------------------------- /public/detail/d2_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail/d2_4.png -------------------------------------------------------------------------------- /public/detail/d2_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail/d2_5.png -------------------------------------------------------------------------------- /public/detail/d2_6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail/d2_6.png -------------------------------------------------------------------------------- /public/detail/d3_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail/d3_1.png -------------------------------------------------------------------------------- /public/detail/d3_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail/d3_2.png -------------------------------------------------------------------------------- /public/detail/d3_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail/d3_3.png -------------------------------------------------------------------------------- /public/detail/d3_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail/d3_4.png -------------------------------------------------------------------------------- /public/detail/d3_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail/d3_5.png -------------------------------------------------------------------------------- /public/detail/d3_6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail/d3_6.png -------------------------------------------------------------------------------- /public/detail/d4_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail/d4_1.png -------------------------------------------------------------------------------- /public/detail/d4_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail/d4_2.png -------------------------------------------------------------------------------- /public/detail/d4_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail/d4_3.png -------------------------------------------------------------------------------- /public/detail/d4_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail/d4_4.png -------------------------------------------------------------------------------- /public/detail/d4_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail/d4_5.png -------------------------------------------------------------------------------- /public/detail/d4_6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail/d4_6.png -------------------------------------------------------------------------------- /public/detail/d4_7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail/d4_7.jpg -------------------------------------------------------------------------------- /public/detail/d5_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail/d5_1.png -------------------------------------------------------------------------------- /public/detail/d5_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail/d5_2.png -------------------------------------------------------------------------------- /public/detail/d5_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail/d5_3.png -------------------------------------------------------------------------------- /public/detail/d5_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail/d5_4.png -------------------------------------------------------------------------------- /public/detail/d5_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail/d5_5.png -------------------------------------------------------------------------------- /public/detail/d5_6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail/d5_6.png -------------------------------------------------------------------------------- /public/detail/d5_7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail/d5_7.png -------------------------------------------------------------------------------- /public/detail/d6_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail/d6_1.png -------------------------------------------------------------------------------- /public/detail/d6_2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail/d6_2.jpg -------------------------------------------------------------------------------- /public/detail/d6_3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail/d6_3.jpg -------------------------------------------------------------------------------- /public/detail/d6_4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail/d6_4.jpg -------------------------------------------------------------------------------- /public/detail/d6_5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail/d6_5.jpg -------------------------------------------------------------------------------- /public/detail/d6_6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail/d6_6.jpg -------------------------------------------------------------------------------- /public/detail/d7_1.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail/d7_1.webp -------------------------------------------------------------------------------- /public/detail/d7_2.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail/d7_2.webp -------------------------------------------------------------------------------- /public/detail/d7_3.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail/d7_3.webp -------------------------------------------------------------------------------- /public/detail/d7_4.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail/d7_4.webp -------------------------------------------------------------------------------- /public/detail/d7_5.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail/d7_5.webp -------------------------------------------------------------------------------- /public/detail/d7_6.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/detail/d7_6.webp -------------------------------------------------------------------------------- /public/favicons/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/favicons/android-chrome-192x192.png -------------------------------------------------------------------------------- /public/favicons/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/favicons/android-chrome-512x512.png -------------------------------------------------------------------------------- /public/favicons/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/favicons/apple-touch-icon.png -------------------------------------------------------------------------------- /public/favicons/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | #da532c 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /public/favicons/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/favicons/favicon-16x16.png -------------------------------------------------------------------------------- /public/favicons/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/favicons/favicon-32x32.png -------------------------------------------------------------------------------- /public/favicons/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/favicons/favicon.ico -------------------------------------------------------------------------------- /public/favicons/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/favicons/mstile-150x150.png -------------------------------------------------------------------------------- /public/fonts/LeagueSpartan-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/fonts/LeagueSpartan-Bold.ttf -------------------------------------------------------------------------------- /public/fonts/LeagueSpartan-ExtraLight.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/fonts/LeagueSpartan-ExtraLight.ttf -------------------------------------------------------------------------------- /public/fonts/LeagueSpartan-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/fonts/LeagueSpartan-Regular.ttf -------------------------------------------------------------------------------- /public/home/home1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/home/home1.jpg -------------------------------------------------------------------------------- /public/home/home2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/home/home2.jpg -------------------------------------------------------------------------------- /public/home/home3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/home/home3.jpg -------------------------------------------------------------------------------- /public/home/home4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nam-Hai/nam-hai-2022/d9dae85d6a53ab2a6f172c6f7a5211aa0191724f/public/home/home4.jpg -------------------------------------------------------------------------------- /site.webmanifest: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Nam Hai Portfolio", 3 | "short_name": "Effect Reproduction", 4 | "icons": [ 5 | { 6 | "src": "favicons/android-chrome-192x192.png", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | }, 10 | { 11 | "src": "favicons/android-chrome-512x512.png", 12 | "sizes": "512x512", 13 | "type": "image/png" 14 | } 15 | ], 16 | "theme_color": "#ffffff", 17 | "background_color": "#ffffff", 18 | "display": "standalone" 19 | } 20 | -------------------------------------------------------------------------------- /src/Canvas/Collections/BasicVer.glsl: -------------------------------------------------------------------------------- 1 | #define PI 3.1415926535 2 | attribute vec2 uv; 3 | attribute vec3 position; 4 | 5 | uniform mat4 modelViewMatrix; 6 | uniform mat4 projectionMatrix; 7 | 8 | varying vec2 vUv; 9 | 10 | void main() { 11 | vUv = uv; 12 | vec4 newPos = modelViewMatrix* vec4(position, 1.0); 13 | gl_Position = projectionMatrix * newPos; 14 | } 15 | -------------------------------------------------------------------------------- /src/Canvas/Collections/BufferFrag.glsl: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | varying vec2 vUv; 3 | uniform float x; 4 | uniform float y; 5 | uniform vec2 resolution; 6 | uniform sampler2D tMap; 7 | uniform vec2 uVelo; 8 | 9 | void main() { 10 | vec4 oldTexture = texture2D(tMap, vUv) * 0.88; 11 | float tileWidth = 30.; 12 | vec2 gridWidth = vec2(resolution.x / tileWidth, resolution.y / tileWidth); 13 | 14 | float largeur = 6.; 15 | 16 | vec2 newO = vec2(ceil(x*gridWidth.x), ceil(y * gridWidth.y))/ largeur; 17 | vec2 newP = vec2(ceil(vUv.xy * gridWidth.xy))/largeur; 18 | 19 | vec2 D = vec2(newO.x - newP.x, newO.y - newP.y); 20 | float d = sqrt(D.x * D.x ); 21 | 22 | float f = clamp((1. - abs(d)), 0. , 1.); 23 | // f= pow(f, .8); 24 | 25 | // vec3 color = vec3(f * abs(uVelo.x),0., f * abs(uVelo.y)); 26 | // gl_FragColor = vec4(vec3(oldTexture) + color * length(uVelo) , 1.); 27 | 28 | 29 | // vec3 color = vec3(f * abs(uVelo.x),0., f * abs(uVelo.y)); 30 | // vec3 color = vec3(f * max(uVelo.x, 0.),f* max(-uVelo.x,0.), f * max(uVelo.y, 0.)); 31 | // gl_FragColor = vec4(vec3(oldTexture) + color * length(uVelo) , 1.); 32 | 33 | vec4 color = vec4(f * max(uVelo.x, 0.),f* max(-uVelo.x,0.), 0.,0.); 34 | gl_FragColor = vec4(oldTexture +0.75* color * length(uVelo) ); 35 | } 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /src/Canvas/Collections/LastFrag.glsl: -------------------------------------------------------------------------------- 1 | precision mediump float; 2 | uniform sampler2D tMap; 3 | uniform sampler2D tGridFlow; 4 | 5 | varying vec2 vUv; 6 | 7 | void main() { 8 | // vec4 texture = texture2D(tMap,vUv); 9 | // vec4 gridflow = texture2D(tGridFlow, vUv); 10 | // gl_FragColor = gridflow; 11 | float p = 30.; 12 | 13 | vec4 gridFlow = texture2D(tGridFlow, vUv); 14 | 15 | 16 | vec4 texture = texture2D(tMap, (vUv - vec2(gridFlow.r - gridFlow.g, gridFlow.b -gridFlow.a)/p )); 17 | if(texture.a < 0.1) { 18 | discard; 19 | } 20 | // gl_FragColor = vec4(vec3(gridFlow), 1.); 21 | gl_FragColor = vec4(vec3(texture), 1.); 22 | } 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/Canvas/Collections/Media.js: -------------------------------------------------------------------------------- 1 | import { Transform, Plane, Program, Mesh, Texture } from 'ogl' 2 | import { collectionsService } from '../../animation/collectionsAnimationService' 3 | import fragment from './fragment.glsl?raw' 4 | import vertex from './vertex.glsl?raw' 5 | 6 | export default class { 7 | constructor({ el, gl, geometry, scene, canvasSize, canvasSizePixel, index }) { 8 | this.index = index 9 | this.gl = gl 10 | this.el = el 11 | this.geometry = geometry 12 | this.scene = scene 13 | this.canvasSize = canvasSize 14 | this.canvasSizePixel = canvasSizePixel 15 | 16 | this.createTexture() 17 | this.createProgram() 18 | this.mesh = new Mesh(this.gl, { 19 | geometry, 20 | program: this.program 21 | }) 22 | 23 | this.getBounds() 24 | this.mesh.setParent(scene) 25 | 26 | } 27 | 28 | 29 | 30 | createTexture() { 31 | this.texture = new Texture(this.gl) 32 | if (this.index) { 33 | collectionsService.getBufferImg(this, this.index) 34 | } 35 | } 36 | 37 | createProgram() { 38 | this.program = new Program(this.gl, { 39 | vertex, 40 | fragment, 41 | uniforms: { 42 | tMap: { 43 | value: this.texture 44 | }, 45 | target: { 46 | value: 5 47 | }, 48 | force: { 49 | value: .5 50 | }, 51 | radius: { 52 | value: 2 53 | }, 54 | angle: { 55 | value: 0.3 56 | }, 57 | s: { 58 | value: [1, 1] 59 | }, 60 | t: { 61 | value: [0, 0] 62 | } 63 | } 64 | }) 65 | } 66 | onResize(canvasSize, canvasSizePixel) { 67 | this.canvasSize = canvasSize 68 | this.canvasSizePixel = canvasSizePixel 69 | } 70 | 71 | getBounds() { 72 | this.boundsPixel = this.el.getBoundingClientRect() 73 | this.bounds = { 74 | width: this.boundsPixel.width * this.canvasSize.width / this.canvasSizePixel.width, 75 | height: this.boundsPixel.height * this.canvasSize.height / this.canvasSizePixel.height 76 | } 77 | 78 | this.setScale() 79 | } 80 | setScale() { 81 | this.program.uniforms.s.value = [this.bounds.height / this.bounds.width, 1] 82 | this.program.uniforms.t.value = [0, 0] 83 | 84 | this.mesh.scale.x = this.bounds.width 85 | this.mesh.scale.y = this.bounds.height 86 | 87 | 88 | this.mesh.position.x = (this.boundsPixel.x - this.canvasSizePixel.width / 2) * this.canvasSize.width / this.canvasSizePixel.width + this.bounds.width / 2 89 | this.mesh.position.y = (-this.boundsPixel.y + this.canvasSizePixel.height / 2) * this.canvasSize.height / this.canvasSizePixel.height - this.bounds.height / 2 90 | } 91 | 92 | 93 | } 94 | -------------------------------------------------------------------------------- /src/Canvas/Collections/collectionsCanvas.js: -------------------------------------------------------------------------------- 1 | import { N } from "../../utils/namhai" 2 | import { Transform, Plane, RenderTarget, Vec2, Program, Mesh, Texture } from 'ogl' 3 | import Media from "./Media" 4 | import BasicVer from './BasicVer.glsl?raw' 5 | import BufferFrag from './BufferFrag.glsl?raw' 6 | import LastFrag from './LastFrag.glsl?raw' 7 | import { Clock } from "../../classes/Timer" 8 | 9 | export default class { 10 | constructor({ gl, scene, canvasSize, canvasSizePixel, canvas }) { 11 | this.gl = gl 12 | this.scene = scene 13 | this.canvasSize = canvasSize 14 | this.canvasSizePixel = canvasSizePixel 15 | 16 | this.group = new Transform() 17 | this.mousemoveON = true 18 | 19 | this.collectionsImg = N.getAll('.display__container img') 20 | this.geometry = new Plane(this.gl, { 21 | heightSegments: 20, 22 | widthSegments: 80 23 | }) 24 | 25 | this.mediaRenderTarget = new RenderTarget(this.gl) 26 | this.medias = Object.entries(this.collectionsImg).map(([index, el]) => { 27 | return new Media({ el, gl, scene: this.group, canvasSize, canvasSizePixel, geometry: this.geometry, index }) 28 | }) 29 | 30 | this.mediasBuffer = Object.entries(this.collectionsImg).map(([index, el]) => { 31 | return new Media({ el, gl, scene: this.group, canvasSize, canvasSizePixel, geometry: this.geometry }) 32 | }) 33 | 34 | this.clock = new Clock() 35 | this.mouse = new Vec2(-1) 36 | this.oldMouse = new Vec2() 37 | this.velo = new Vec2(-1) 38 | this.uVelo = new Vec2() 39 | this.delta = 0 40 | this.canvas = canvas 41 | 42 | this.bufferRenderObject = this.createPlaneBuffer() 43 | this.createLastPlane() 44 | 45 | // this.group.setParent(this.scene) 46 | 47 | 48 | } 49 | 50 | init(s) { 51 | this.canvas.raf.stop() 52 | this.canvas.raf = new N.RafR(() => { 53 | if (!this.velo.needsUpdate) { 54 | this.mouse.set(-1) 55 | this.velo.set(0) 56 | } 57 | this.velo.needsUpdate = false 58 | 59 | this.uVelo.lerp(this.velo, !!this.velo.len() ? 0.1 : 0.1) 60 | 61 | this.bufferRenderObject.mesh.program.uniforms.uVelo.value = this.uVelo 62 | 63 | this.canvas.renderer.render({ 64 | camera: this.canvas.camera, 65 | scene: this.bufferRenderObject.scene, 66 | target: this.mask.write, 67 | clear: false 68 | }) 69 | this.mask.swap() 70 | 71 | this.canvas.renderer.render({ 72 | scene: this.group, 73 | target: this.mediaRenderTarget, 74 | camera: this.canvas.camera 75 | }) 76 | 77 | 78 | // this.bufferRenderObject.mesh.program.uniforms.tMap.value = this.mask.target.texture 79 | 80 | // this.medias.program.uniforms.tMap.value = this.uniform 81 | 82 | this.lastPlane.program.uniforms.tMap.value = this.mediaRenderTarget.texture 83 | 84 | this.canvas.renderer.render({ 85 | scene: this.scene, 86 | camera: this.canvas.camera, 87 | }) 88 | }) 89 | this.canvas.raf.run() 90 | if (s) { 91 | s() 92 | } 93 | } 94 | 95 | onMouseMove(e) { 96 | if (!this.mousemoveON) return 97 | let bY = this.collectionBounds.y < 0 ? this.collectionBounds.y + this.canvasSizePixel.height : this.collectionBounds.y 98 | if (e.x < this.collectionBounds.x || e.x > this.collectionBounds.x + this.collectionBounds.width || e.y < bY || e.y > bY + this.collectionBounds.height) { 99 | return 100 | } 101 | this.oldMouse.copy(this.mouse) 102 | // this.scroll.target += e.deltaY / 100 103 | // const x = (e.x - this.collectionBounds.x) / this.collectionBounds.width 104 | // const bY = this.collectionBounds.y + this.canvasSizePixel.height 105 | // const y = 1 - N.iLerp(e.y, bY, this.collectionBounds.height + bY) 106 | 107 | const x = e.x / this.canvasSizePixel.width 108 | const y = 1 - e.y / this.canvasSizePixel.height 109 | this.bufferRenderObject.mesh.program.uniforms.x.value = x 110 | this.bufferRenderObject.mesh.program.uniforms.y.value = y 111 | 112 | this.mouse.set(x, y) 113 | 114 | let delta = this.clock.getDelta() || 14 115 | this.velo.x = N.Clamp(5 * (this.mouse.x - this.oldMouse.x) / delta, -1, 1) 116 | this.velo.y = N.Clamp(1 * (this.mouse.y - this.oldMouse.y) / delta, -1, 1) 117 | this.velo.needsUpdate = true 118 | 119 | } 120 | 121 | createPlaneBuffer() { 122 | 123 | let sceneBuffer = new Transform() 124 | 125 | this.uniform = { value: null } 126 | this.collectionBounds = N.get('.display__container a.link__spa').getBoundingClientRect() 127 | 128 | let gl = this.gl 129 | let type = gl.HALF_FLOAT 130 | let minFilter = (() => { 131 | if (gl.renderer.isWebgl2) return gl.LINEAR; 132 | if (gl.renderer.extensions[`OES_texture_${type === gl.FLOAT ? '' : 'half_'}float_linear`]) return gl.LINEAR; 133 | return gl.NEAREST; 134 | })(); 135 | let option = { 136 | width: this.canvasSizePixel.width, 137 | height: this.canvasSizePixel.height, 138 | minFilter, 139 | internalFormat: gl.renderer.isWebgl2 ? (type === gl.FLOAT ? gl.RGBA32F : gl.RGBA16F) : gl.RGBA, 140 | format: gl.RGBA, 141 | depth: false, 142 | type 143 | } 144 | 145 | this.mask = { 146 | write: new RenderTarget(this.gl, option), 147 | read: new RenderTarget(this.gl, option), 148 | swap: _ => { 149 | let temp = this.mask.read 150 | this.mask.read = this.mask.write 151 | this.mask.write = temp 152 | this.uniform.value = this.mask.read.texture 153 | } 154 | } 155 | this.mask.swap() 156 | const resolution = { value: new Vec2() } 157 | // resolution.value.set(this.gl.canvas.width, this.gl.canvas.height) 158 | resolution.value.set(this.collectionBounds.width, this.collectionBounds.height) 159 | let programBuffer = new Program(this.gl, { 160 | fragment: BufferFrag, 161 | vertex: BasicVer, 162 | uniforms: { 163 | tMap: this.uniform, 164 | resolution, 165 | x: { 166 | value: .5 167 | }, 168 | y: { 169 | value: 0 170 | }, 171 | uVelo: { 172 | value: this.uVelo 173 | } 174 | }, 175 | // depthTest: false 176 | }) 177 | 178 | let backgroundBufferMesh = new Mesh(this.gl, { 179 | geometry: new Plane(this.gl), 180 | program: programBuffer, 181 | }) 182 | 183 | let renderObject = { 184 | mesh: backgroundBufferMesh, scene: sceneBuffer, 185 | } 186 | 187 | backgroundBufferMesh.setParent(sceneBuffer) 188 | backgroundBufferMesh.scale.x = this.canvasSize.width 189 | backgroundBufferMesh.scale.y = this.canvasSize.height 190 | 191 | // backgroundBufferMesh.scale.x = this.collectionBounds.width / this.canvasSizePixel.width * this.canvasSize.width 192 | // backgroundBufferMesh.scale.y = this.collectionBounds.height / this.canvasSizePixel.height * this.canvasSize.height 193 | 194 | // backgroundBufferMesh.position.x = 0 195 | // backgroundBufferMesh.position.y = (-this.canvasSizePixel.height / 2 - this.collectionBounds.y - this.collectionBounds.height / 2) / this.canvasSizePixel.height * this.canvasSize.height 196 | 197 | return renderObject 198 | } 199 | createLastPlane() { 200 | this.lastPlane = new Mesh(this.gl, { 201 | geometry: new Plane(this.gl), 202 | program: new Program(this.gl, { 203 | vertex: BasicVer, 204 | fragment: LastFrag, 205 | uniforms: { 206 | tGridFlow: this.uniform, 207 | tMap: { 208 | value: new Texture(this.gl) 209 | } 210 | } 211 | }) 212 | }) 213 | this.lastPlane.scale.y = this.canvasSize.height 214 | this.lastPlane.scale.x = this.canvasSize.width 215 | 216 | this.lastPlane.setParent(this.scene) 217 | } 218 | update(t) { 219 | 220 | if (!this.velo.needsUpdate) { 221 | this.mouse.set(-1) 222 | this.velo.set(0) 223 | } 224 | this.velo.needsUpdate = false 225 | 226 | // this.uVelo.target = 0.5 * Math.sqrt(this.velo.x ** 2 + this.velo.y ** 2) 227 | // this.uVelo.cur = N.Lerp(this.uVelo.cur, this.uVelo.target, !!this.uVelo.target ? 0.1 : 0.05) 228 | this.uVelo.lerp(this.velo, !!this.velo.len() ? 0.1 : 0.05) 229 | 230 | 231 | // this.bufferRenderObject.mesh.program.uniforms.uVelo.value = N.Clamp(this.uVelo.cur, 0, 1) 232 | this.bufferRenderObject.mesh.program.uniforms.uVelo.value = this.uVelo 233 | 234 | this.renderer.render({ 235 | camera: this.camera, 236 | scene: this.bufferRenderObject.scene, 237 | target: this.mask.write, 238 | clear: false 239 | }) 240 | this.mask.swap() 241 | 242 | // this.bufferRenderObject.mesh.program.uniforms.tMap.value = this.mask.target.texture 243 | 244 | // this.gallery[0].program.uniforms.tMap.value = this.uniform 245 | 246 | this.renderer.render({ 247 | scene: this.scene, 248 | camera: this.camera, 249 | }) 250 | } 251 | onResize(canvasSizePixel, canvasSize) { 252 | this.canvasSizePixel = canvasSizePixel; 253 | this.canvasSize = canvasSize; 254 | [...this.medias, ...this.mediasBuffer].forEach(m => { 255 | m.onResize(this.canvasSize, this.canvasSizePixel) 256 | }) 257 | 258 | this.collectionBounds = N.get('.display__container a.link__spa').getBoundingClientRect() 259 | this.lastPlane.scale.y = this.canvasSize.height 260 | this.lastPlane.scale.x = this.canvasSize.width 261 | this.bufferRenderObject.mesh.scale.x = this.canvasSize.width 262 | this.bufferRenderObject.mesh.scale.y = this.canvasSize.height 263 | this.bufferRenderObject.mesh.program.uniforms.resolution.value.set(this.collectionBounds.width, this.collectionBounds.height) 264 | this.getBounds() 265 | } 266 | 267 | getBounds() { 268 | [...this.medias, ...this.mediasBuffer].forEach(m => { 269 | m.getBounds(this.canvasSize, this.canvasSizePixel) 270 | }) 271 | } 272 | 273 | destroy() { 274 | this.scene.removeChild(this.lastPlane) 275 | this.canvas.raf.stop() 276 | this.canvas.raf = new N.RafR(this.canvas.update) 277 | this.canvas.raf.run() 278 | this.medias.forEach(m => { 279 | m.scene.removeChild(m.mesh) 280 | m = null 281 | }) 282 | this.scene.removeChild(this.group) 283 | } 284 | 285 | hide() { 286 | this.destroy() 287 | } 288 | } 289 | -------------------------------------------------------------------------------- /src/Canvas/Collections/fragment.glsl: -------------------------------------------------------------------------------- 1 | precision mediump float; 2 | uniform sampler2D tMap; 3 | 4 | varying vec2 vUv; 5 | 6 | void main() { 7 | vec4 texture = texture2D(tMap,vUv); 8 | gl_FragColor = texture; 9 | } 10 | 11 | -------------------------------------------------------------------------------- /src/Canvas/Collections/vertex.glsl: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | 3 | float io2(float t) { 4 | float p = 2.0 * t * t; 5 | return t < 0.5 ? p : -p + (4.0 * t) - 1.0; 6 | } 7 | 8 | attribute vec2 uv; 9 | attribute vec3 position; 10 | 11 | uniform mat4 modelViewMatrix; 12 | uniform mat4 projectionMatrix; 13 | 14 | uniform float target; 15 | uniform float force; 16 | uniform float radius; 17 | uniform float angle; 18 | 19 | uniform vec2 s; 20 | uniform vec2 t; 21 | 22 | varying vec2 vUv; 23 | 24 | void main() { 25 | 26 | vec4 canvasPos = modelViewMatrix * vec4(position, 1.0); 27 | float l = abs(canvasPos.x - angle * canvasPos.y - target); 28 | canvasPos.z -= (force - io2(l/radius) * force) * step(l,radius); 29 | gl_Position = projectionMatrix * canvasPos; 30 | 31 | 32 | vUv = (uv - .5)/s+ .5 + t; 33 | } 34 | 35 | -------------------------------------------------------------------------------- /src/Canvas/Contact/contactCanvas.js: -------------------------------------------------------------------------------- 1 | import { N } from "../../utils/namhai" 2 | import { Transform, Plane, Program, Mesh, Texture } from 'ogl' 3 | import fragment from './fragment.glsl?raw' 4 | import vertex from './vertex.glsl?raw' 5 | import { TEXTURE } from "../Preloader/preloaderCanvas" 6 | import { contactService } from "../../animation/contactAnimation" 7 | 8 | export default class { 9 | constructor({ gl, scene, canvasSize, canvasSizePixel }) { 10 | this.gl = gl 11 | this.scene = scene 12 | this.canvasSize = canvasSize 13 | this.canvasSizePixel = canvasSizePixel 14 | 15 | this.group = new Transform() 16 | this.hero = N.get('.contact__container img') 17 | 18 | this.createMesh() 19 | this.getBounds() 20 | this.group.setParent(this.scene) 21 | 22 | let motionInit = new N.TL() 23 | this.nextTL = new N.TL() 24 | this.init = false 25 | 26 | motionInit.from({ 27 | d: 2000, 28 | update: t => { 29 | this.program.uniforms.u_time.value = t.progE 30 | }, 31 | cb: _ => { 32 | this.program.uniforms.u_init.value = true; 33 | this.program.uniforms.u_time.value = 0; 34 | this.program.uniforms.u_force.value = 0; 35 | this.program.uniforms.u_ftime.value = 0; 36 | this.init = true 37 | } 38 | }) 39 | motionInit.from({ 40 | d: 1000, 41 | delay: 1000, 42 | ease: 'linear', 43 | update: t => { 44 | this.program.uniforms.u_force.value = t.progE 45 | } 46 | }) 47 | motionInit.play() 48 | N.BM(this, ['update']) 49 | 50 | this.raf = new N.RafR(this.update) 51 | this.raf.run() 52 | } 53 | 54 | createTexture() { 55 | this.texture = new Texture(this.gl) 56 | this.texture.image = TEXTURE.get(contactService.getInfo().texture).image 57 | 58 | this.textureBuffer = new Texture(this.gl) 59 | this.textureBuffer.image = TEXTURE.get(contactService.getNextInfo().texture).image 60 | } 61 | 62 | createMesh() { 63 | this.createTexture() 64 | this.program = new Program(this.gl, { 65 | fragment, 66 | vertex, 67 | uniforms: { 68 | tMap: { 69 | value: this.texture 70 | }, 71 | tMapBuffer: { 72 | value: this.textureBuffer 73 | }, 74 | ratio: { 75 | value: 1 76 | }, 77 | u_time: { 78 | value: 0 79 | }, 80 | u_ftime: { 81 | value: 0 82 | }, 83 | u_force: { 84 | value: 0 85 | }, 86 | u_maxDim: { 87 | value: 1 88 | }, 89 | u_init: { 90 | value: false 91 | }, 92 | u_rand: { 93 | value: 0 94 | } 95 | } 96 | }) 97 | 98 | this.geometry = new Plane(this.gl, { 99 | heightSegments: 80, 100 | widthSegments: 80 101 | }) 102 | 103 | this.mesh = new Mesh(this.gl, { 104 | geometry: this.geometry, 105 | program: this.program 106 | }) 107 | this.mesh.setParent(this.group) 108 | } 109 | 110 | onResize(canvasSizePixel, canvasSize) { 111 | this.canvasSize = canvasSize 112 | this.canvasSizePixel = canvasSizePixel 113 | this.getBounds() 114 | } 115 | getBounds() { 116 | this.heroBoundsPixel = this.hero.getBoundingClientRect() 117 | this.heroBounds = { 118 | width: this.heroBoundsPixel.width * this.canvasSize.width / this.canvasSizePixel.width, 119 | height: this.heroBoundsPixel.height * this.canvasSize.height / this.canvasSizePixel.height 120 | } 121 | 122 | this.program.uniforms.ratio.value = this.heroBounds.height / this.heroBounds.width 123 | this.program.uniforms.u_maxDim.value = this.heroBounds.height; 124 | this.setScalePos() 125 | } 126 | 127 | setScalePos() { 128 | if (!this.mesh) return 129 | 130 | this.mesh.scale.x = this.heroBounds.width 131 | this.mesh.scale.y = this.heroBounds.height 132 | this.mesh.position.x = 0 133 | this.mesh.position.y = 0 134 | } 135 | 136 | update() { 137 | 138 | } 139 | 140 | destroy() { 141 | this.raf.stop() 142 | this.group.removeChild(this.mesh) 143 | this.mesh = null; 144 | this.scene.removeChild(this.group) 145 | } 146 | 147 | async hide() { 148 | this.destroy() 149 | } 150 | 151 | } 152 | 153 | -------------------------------------------------------------------------------- /src/Canvas/Contact/fragment.glsl: -------------------------------------------------------------------------------- 1 | precision mediump float; 2 | uniform sampler2D tMap; 3 | uniform sampler2D tMapBuffer; 4 | uniform float ratio; 5 | uniform float u_time; 6 | uniform float u_force; 7 | uniform float u_maxDim; 8 | uniform bool u_init; 9 | uniform float u_rand; 10 | varying vec2 vUv; 11 | 12 | vec3 mod289(vec3 x) { 13 | return x - floor(x * (1.0 / 289.0)) * 289.0; 14 | } 15 | 16 | vec4 mod289(vec4 x) { 17 | return x - floor(x * (1.0 / 289.0)) * 289.0; 18 | } 19 | 20 | vec4 permute(vec4 x) { 21 | return mod289(((x*34.0)+1.0)*x); 22 | } 23 | 24 | vec4 taylorInvSqrt(vec4 r) 25 | { 26 | return 1.79284291400159 - 0.85373472095314 * r; 27 | } 28 | 29 | float snoise(vec3 v) 30 | { 31 | const vec2 C = vec2(1.0/6.0, 1.0/3.0) ; 32 | const vec4 D = vec4(0.0, 0.5, 1.0, 2.0); 33 | 34 | vec3 i = floor(v + dot(v, C.yyy) ); 35 | vec3 x0 = v - i + dot(i, C.xxx) ; 36 | vec3 g = step(x0.yzx, x0.xyz); 37 | vec3 l = 1.0 - g; 38 | vec3 i1 = min( g.xyz, l.zxy ); 39 | vec3 i2 = max( g.xyz, l.zxy ); 40 | vec3 x1 = x0 - i1 + C.xxx; 41 | vec3 x2 = x0 - i2 + C.yyy; 42 | vec3 x3 = x0 - D.yyy; 43 | i = mod289(i); 44 | vec4 p = permute( permute( permute( 45 | i.z + vec4(0.0, i1.z, i2.z, 1.0 )) 46 | + i.y + vec4(0.0, i1.y, i2.y, 1.0 )) 47 | + i.x + vec4(0.0, i1.x, i2.x, 1.0 )); 48 | float n_ = 0.142857142857; 49 | vec3 ns = n_ * D.wyz - D.xzx; 50 | 51 | vec4 j = p - 49.0 * floor(p * ns.z * ns.z); 52 | vec4 x_ = floor(j * ns.z); 53 | vec4 y_ = floor(j - 7.0 * x_ ); 54 | vec4 x = x_ *ns.x + ns.yyyy; 55 | vec4 y = y_ *ns.x + ns.yyyy; 56 | vec4 h = 1.0 - abs(x) - abs(y); 57 | vec4 b0 = vec4( x.xy, y.xy ); 58 | vec4 b1 = vec4( x.zw, y.zw ); 59 | vec4 s0 = floor(b0)*2.0 + 1.0; 60 | vec4 s1 = floor(b1)*2.0 + 1.0; 61 | vec4 sh = -step(h, vec4(0.0)); 62 | vec4 a0 = b0.xzyw + s0.xzyw*sh.xxyy ; 63 | vec4 a1 = b1.xzyw + s1.xzyw*sh.zzww ; 64 | vec3 p0 = vec3(a0.xy,h.x); 65 | vec3 p1 = vec3(a0.zw,h.y); 66 | vec3 p2 = vec3(a1.xy,h.z); 67 | vec3 p3 = vec3(a1.zw,h.w); 68 | vec4 norm = taylorInvSqrt(vec4(dot(p0,p0), dot(p1,p1), dot(p2, p2), dot(p3,p3))); 69 | p0 *= norm.x; 70 | p1 *= norm.y; 71 | p2 *= norm.z; 72 | p3 *= norm.w; 73 | vec4 m = max(0.6 - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0); 74 | m = m * m; 75 | return 42.0 * dot( m*m, vec4( dot(p0,x0), dot(p1,x1), 76 | dot(p2,x2), dot(p3,x3) ) ); 77 | } 78 | 79 | float circle(in vec2 _st, in float _radius, in float blurriness){ 80 | vec2 dist = _st; 81 | return 1.-smoothstep(_radius-(_radius*blurriness), _radius+(_radius*blurriness), dot(dist,dist)*4.0); 82 | } 83 | 84 | void main() { 85 | float c = circle(vec2(vUv.x - 0.5,(vUv.y - .5)*ratio),u_time* u_maxDim ,0.9) * 2.5; 86 | float n = (snoise(vec3(vUv.x, vUv.y, u_rand + u_time* .25)* 3.) + mix(0.1, 2.0, u_force))* 1. ; 87 | float mask = smoothstep(0.49, .5, c * n); 88 | vec4 texture =texture2D(tMap,vUv); 89 | vec4 textureBuffer = texture2D(tMapBuffer, vUv); 90 | if(u_init == false) 91 | gl_FragColor = mix(vec4(.0,.0,.0,.0), texture, mask); 92 | else 93 | gl_FragColor = mix(texture, textureBuffer,mask); 94 | 95 | } 96 | -------------------------------------------------------------------------------- /src/Canvas/Contact/vertex.glsl: -------------------------------------------------------------------------------- 1 | #define PI 3.1415 2 | precision mediump float; 3 | 4 | attribute vec2 uv; 5 | attribute vec3 position; 6 | 7 | uniform mat4 modelViewMatrix; 8 | uniform mat4 projectionMatrix; 9 | uniform float u_ftime; 10 | 11 | varying vec2 vUv; 12 | 13 | void main() { 14 | vUv = uv; 15 | 16 | float newZ = -(cos(position.x * PI) / 2.0+ cos(position.y * PI)/ 2.0)*u_ftime * 1.5; 17 | gl_Position = projectionMatrix * modelViewMatrix * vec4(position.x, position.y, newZ, 1.0); 18 | } 19 | 20 | -------------------------------------------------------------------------------- /src/Canvas/Demo/demoCanvas.js: -------------------------------------------------------------------------------- 1 | import { N } from "../../utils/namhai" 2 | import { Transform, Plane, Program, Mesh, Texture } from 'ogl' 3 | import fragment from './fragment.glsl?raw' 4 | import vertex from './vertex.glsl?raw' 5 | 6 | export default class { 7 | constructor({ gl, scene, canvasSize, canvasSizePixel }) { 8 | this.gl = gl 9 | this.scene = scene 10 | this.canvasSize = canvasSize 11 | this.canvasSizePixel = canvasSizePixel 12 | 13 | this.group = new Transform() 14 | 15 | this.button = N.get('ressort-button') 16 | 17 | this.createMesh() 18 | this.getBounds() 19 | 20 | this.group.setParent(scene) 21 | } 22 | 23 | createMesh() { 24 | this.program = new Program(this.gl, { 25 | fragment, 26 | vertex, 27 | uniforms: { 28 | o: { 29 | value: 0 30 | }, 31 | fade: { 32 | value: 0 33 | }, 34 | force: { 35 | value: 0 36 | }, 37 | radius: { 38 | value: 2 39 | }, 40 | s: { 41 | value: [1, 1] 42 | } 43 | } 44 | }) 45 | 46 | this.geometry = new Plane(this.gl, { 47 | heightSegments: 80, 48 | widthSegments: 80 49 | }) 50 | 51 | this.mesh = new Mesh(this.gl, { 52 | geometry: this.geometry, 53 | program: this.program 54 | }) 55 | this.mesh.setParent(this.group) 56 | } 57 | 58 | getBounds() { 59 | this.buttonBoundsPixel = this.button.getBoundingClientRect() 60 | this.buttonBounds = { 61 | width: this.buttonBoundsPixel.width * this.canvasSize.width / this.canvasSizePixel.width, 62 | height: this.buttonBoundsPixel.height * this.canvasSize.height / this.canvasSizePixel.height 63 | } 64 | 65 | 66 | this.setScalePos() 67 | } 68 | 69 | setScalePos() { 70 | 71 | this.program.uniforms.s.value = [1.93814 * this.canvasSize.height / this.canvasSize.width, 1] 72 | this.mesh.scale.x = this.buttonBounds.width 73 | this.mesh.scale.y = this.buttonBounds.height 74 | this.mesh.position.x = 0 75 | this.mesh.position.y = 0 76 | } 77 | 78 | async hide() { 79 | this.group.removeChild(this.mesh) 80 | this.scene.removeChild(this.group) 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /src/Canvas/Demo/fragment.glsl: -------------------------------------------------------------------------------- 1 | precision mediump float; 2 | uniform float o; 3 | uniform float fade; 4 | 5 | varying vec2 vUv; 6 | 7 | void main() { 8 | gl_FragColor = vec4(1.0,1.0,1.0, o); 9 | } 10 | -------------------------------------------------------------------------------- /src/Canvas/Demo/vertex.glsl: -------------------------------------------------------------------------------- 1 | float io2(float t) { 2 | float p = 2.0 * t * t; 3 | return t < 0.5 ? p : -p + (4.0 * t) - 1.0; 4 | } 5 | 6 | attribute vec3 position; 7 | uniform mat4 modelViewMatrix; 8 | uniform mat4 projectionMatrix; 9 | 10 | uniform float force; 11 | uniform float radius; 12 | uniform vec2 s; 13 | 14 | attribute vec2 uv; 15 | varying vec2 vUv; 16 | void main() { 17 | float x = position.x; 18 | float y = position.y; 19 | float d = sqrt(x*x + y*y); 20 | 21 | float z = (force - io2(d/radius) * force) * step(d, radius); 22 | gl_Position = projectionMatrix * modelViewMatrix * vec4(position.x, position.y, z, 1.0); 23 | vUv = (uv - .5)/s+ .5; 24 | } 25 | -------------------------------------------------------------------------------- /src/Canvas/Home/fragment.glsl: -------------------------------------------------------------------------------- 1 | precision mediump float; 2 | uniform sampler2D tMap; 3 | 4 | varying vec2 vUv; 5 | 6 | void main() { 7 | vec4 texture = texture2D(tMap,vUv); 8 | gl_FragColor = texture; 9 | } 10 | 11 | -------------------------------------------------------------------------------- /src/Canvas/Home/homeCanvas.js: -------------------------------------------------------------------------------- 1 | import { N } from "../../utils/namhai" 2 | import { Transform, Plane, Program, Mesh, Texture } from 'ogl' 3 | import fragment from './fragment.glsl?raw' 4 | import vertex from './vertex.glsl?raw' 5 | import { TEXTURE } from "../Preloader/preloaderCanvas" 6 | 7 | export default class { 8 | constructor({ gl, scene, canvasSize, canvasSizePixel }) { 9 | this.gl = gl 10 | this.scene = scene 11 | this.canvasSize = canvasSize 12 | this.canvasSizePixel = canvasSizePixel 13 | 14 | this.group = new Transform() 15 | this.hero = N.get('.hero img') 16 | 17 | } 18 | 19 | createTexture() { 20 | this.texture = new Texture(this.gl) 21 | const src = this.hero.getAttribute('data-src') 22 | this.texture.image = TEXTURE.get(src).image 23 | } 24 | 25 | createMesh() { 26 | this.createTexture() 27 | this.program = new Program(this.gl, { 28 | fragment, 29 | vertex, 30 | uniforms: { 31 | tMap: { 32 | value: this.texture 33 | }, 34 | } 35 | }) 36 | 37 | this.geometry = new Plane(this.gl, { 38 | heightSegments: 1, 39 | widthSegments: 1 40 | }) 41 | 42 | this.mesh = new Mesh(this.gl, { 43 | geometry: this.geometry, 44 | program: this.program 45 | }) 46 | this.mesh.setParent(this.group) 47 | } 48 | 49 | getBounds() { 50 | this.heroBoundsPixel = this.hero.getBoundingClientRect() 51 | this.heroBounds = { 52 | width: this.heroBoundsPixel.width * this.canvasSize.width / this.canvasSizePixel.width, 53 | height: this.heroBoundsPixel.height * this.canvasSize.height / this.canvasSizePixel.height 54 | } 55 | this.setScalePos() 56 | } 57 | 58 | setScalePos() { 59 | if (!this.mesh) return 60 | 61 | this.mesh.scale.x = this.heroBounds.width 62 | this.mesh.scale.y = this.heroBounds.height 63 | this.mesh.position.x = 0 64 | this.mesh.position.y = 0 65 | } 66 | 67 | destroy() { 68 | } 69 | 70 | async hide() { 71 | await new Promise(res => { 72 | let motion = new N.M({ 73 | d: 300, 74 | e: 'o6', 75 | update: t => { 76 | }, 77 | cb: () => { 78 | this.destroy() 79 | res() 80 | }, 81 | }) 82 | motion.play() 83 | }) 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /src/Canvas/Home/vertex.glsl: -------------------------------------------------------------------------------- 1 | attribute vec2 uv; 2 | attribute vec3 position; 3 | 4 | uniform mat4 modelViewMatrix; 5 | uniform mat4 projectionMatrix; 6 | 7 | varying vec2 vUv; 8 | 9 | void main() { 10 | vUv = uv; 11 | 12 | gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); 13 | } 14 | 15 | -------------------------------------------------------------------------------- /src/Canvas/Preloader/preloaderCanvas.js: -------------------------------------------------------------------------------- 1 | import { Texture } from 'ogl' 2 | import { N } from "../../utils/namhai"; 3 | 4 | const ASSETS = [ 5 | 'contact/contact_1.png', 6 | 'contact/contact_2.png', 7 | 'collections/cherifkid1.jpg', 8 | 'collections/cherifkid2.png', 9 | 'collections/noise1.png', 10 | 'collections/noise2.png', 11 | 'collections/travis1.png', 12 | 'collections/travis2.png', 13 | 'collections/wrath1.png', 14 | 'collections/wrath2.png', 15 | 'collections/Jesperish1.jpg', 16 | 'collections/Jesperish2.jpg', 17 | 'collections/raegular1.jpg', 18 | 'collections/raegular2.jpg', 19 | 'collections/jardel1.jpg', 20 | 'collections/jardel2.jpg', 21 | 'contact/contact_1.png', 22 | 'contact/contact_2.png', 23 | 'contact/contact_3.png', 24 | 'home/home1.jpg', 25 | 'home/home2.jpg', 26 | 'home/home3.jpg', 27 | 'home/home4.jpg', 28 | ] 29 | 30 | export const TEXTURE = new Map() 31 | export default class { 32 | constructor({ gl, scene, canvasSize, canvasSizePixel }) { 33 | this.gl = gl 34 | 35 | this.counter = N.getAll('.main .preloader__counter span span') 36 | this.bar = N.get('.preloader__bar') 37 | } 38 | 39 | async loadTexture(cb) { 40 | this.index = 0 41 | for (const assets of ASSETS) { 42 | 43 | const texture = new Texture(this.gl) 44 | const image = new window.Image() 45 | image.crossOrigin = 'anonymous' 46 | image.src = assets 47 | await new Promise(s => { 48 | image.onload = () => { 49 | texture.image = image 50 | this.onLoadedTexture(assets, texture, cb) 51 | s() 52 | } 53 | }) 54 | } 55 | } 56 | 57 | onLoadedTexture(src, texture, cb) { 58 | TEXTURE.set(src, texture) 59 | this.index++ 60 | const count = this.index / ASSETS.length, 61 | r = N.Round(count * 100, 0), 62 | t = N.ZL(r === 100 ? 0 : r) 63 | this.counter[0].innerText = t[0] 64 | this.counter[1].innerText = t[1] 65 | this.bar.style.transform = `scaleX(${(2 + count) * 100}%)` 66 | if (this.index / ASSETS.length == 1) { 67 | this.onComplete(cb) 68 | } 69 | } 70 | 71 | onComplete(cb) { 72 | new N.M({ 73 | el: [...this.counter], 74 | p: { 75 | x: [0, 103] 76 | }, 77 | d: 600, 78 | e: 'o5', 79 | delay: 300, 80 | cb: _ => { 81 | cb() 82 | } 83 | }).play() 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/Canvas/canvas.js: -------------------------------------------------------------------------------- 1 | import { Renderer, Camera, Transform } from 'ogl' 2 | import { N } from '../utils/namhai'; 3 | import CollectionsCanvas from './Collections/collectionsCanvas'; 4 | import ContactCanvas from './Contact/contactCanvas'; 5 | import HomeCanvas from './Home/homeCanvas'; 6 | import DemoCanvas from './Demo/demoCanvas'; 7 | import PreloaderCanvas from './Preloader/preloaderCanvas'; 8 | 9 | class Canvas { 10 | constructor() { 11 | this.mapRouteObject = { 12 | home: this.createHome, 13 | demo: this.createDemo, 14 | collections: this.createCollections, 15 | contact: this.createContact, 16 | preloader: this.createPreloader 17 | }; 18 | 19 | this.sizePixel = { 20 | width: window.innerWidth, 21 | height: window.innerHeight 22 | } 23 | this.createRenderer() 24 | this.createCamera() 25 | this.createScene() 26 | 27 | this.onResize() 28 | 29 | N.BM(this, ['update']) 30 | this.raf = new N.RafR(this.update) 31 | } 32 | 33 | createRenderer() { 34 | this.renderer = new Renderer({ 35 | alpha: true 36 | }) 37 | this.gl = this.renderer.gl 38 | document.body.appendChild(this.gl.canvas) 39 | } 40 | createCamera() { 41 | this.camera = new Camera(this.gl) 42 | this.camera.position.z = 5 43 | } 44 | createScene() { 45 | this.scene = new Transform() 46 | } 47 | 48 | getCurrent() { 49 | return this[this.route] 50 | } 51 | 52 | createDemo() { 53 | this.demo = new DemoCanvas({ 54 | gl: this.gl, 55 | scene: this.scene, 56 | canvasSize: this.size, 57 | canvasSizePixel: this.sizePixel 58 | }) 59 | } 60 | 61 | createPreloader() { 62 | this.preloader = new PreloaderCanvas({ 63 | gl: this.gl, 64 | scene: this.scene, 65 | canvasSize: this.size, 66 | canvasSizePixel: this.sizePixel 67 | }) 68 | } 69 | createHome() { 70 | this.home = new HomeCanvas({ 71 | gl: this.gl, 72 | scene: this.scene, 73 | canvasSize: this.size, 74 | canvasSizePixel: this.sizePixel 75 | }) 76 | } 77 | createCollections() { 78 | this.collections = new CollectionsCanvas({ 79 | gl: this.gl, 80 | scene: this.scene, 81 | canvasSize: this.size, 82 | canvasSizePixel: this.sizePixel, 83 | canvas: this 84 | }) 85 | } 86 | 87 | createContact() { 88 | this.contact = new ContactCanvas({ 89 | gl: this.gl, 90 | scene: this.scene, 91 | canvasSize: this.size, 92 | canvasSizePixel: this.sizePixel 93 | }) 94 | } 95 | 96 | onChange(route) { 97 | this.route = route 98 | if (this.mapRouteObject.hasOwnProperty(route)) { 99 | const createNewObject = this.mapRouteObject[route].bind(this) 100 | createNewObject() 101 | 102 | } 103 | } 104 | 105 | onMouseMove(e) { 106 | let cur = this.getCurrent() 107 | if (cur && cur.onMouseMove) { 108 | cur.onMouseMove(e) 109 | } 110 | } 111 | 112 | onResize(route) { 113 | this.renderer.setSize(window.innerWidth, window.innerHeight) 114 | this.sizePixel = { 115 | width: window.innerWidth, 116 | height: window.innerHeight 117 | } 118 | 119 | this.camera.perspective({ 120 | aspect: this.sizePixel.width / this.sizePixel.height 121 | }) 122 | const fov = this.camera.fov * Math.PI / 180 123 | 124 | const height = 2 * Math.tan(fov / 2) * this.camera.position.z 125 | this.size = { 126 | height: height, 127 | width: height * this.camera.aspect 128 | } 129 | 130 | if (route && this[route] && this[route].onResize) { 131 | this[route].onResize(this.sizePixel, this.size) 132 | } 133 | } 134 | 135 | update() { 136 | this.renderer.render({ 137 | camera: this.camera, 138 | scene: this.scene 139 | }) 140 | 141 | } 142 | 143 | show() { 144 | this.raf.run() 145 | } 146 | async hide(route) { 147 | if (this[route] && this[route].hide) 148 | await this[route].hide() 149 | } 150 | } 151 | 152 | export const canvas = new Canvas() 153 | -------------------------------------------------------------------------------- /src/Pages/Collections/collections.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 31 | 32 |
33 | collections_display_img_1 34 | collections_display_img_2 35 | 36 |
37 |
38 | 39 |
40 | 41 |
42 | Back 43 |
44 | 45 |
46 | 47 | 48 | 49 |
50 |
51 | -------------------------------------------------------------------------------- /src/Pages/Collections/collections.js: -------------------------------------------------------------------------------- 1 | import Page from "../../classes/Page"; 2 | import gridFixation from "../../components/gridFixation/gridFixation"; 3 | import ressortButton from "../../components/ressortButton/ressortButton"; 4 | import { stringLetterToDoubleSpan } from "../../utils/utilsText"; 5 | import collectionsTemplate from './collections.html?raw' 6 | import { N } from "../../utils/namhai"; 7 | import { collectionsService } from "../../animation/collectionsAnimationService"; 8 | import homeFixation from "../../animation/homeFixation"; 9 | 10 | export default class Collections extends Page { 11 | constructor() { 12 | super({ 13 | components: { 14 | 'ressort-button': ressortButton, 15 | 'grid-fixation': gridFixation 16 | }, 17 | content: collectionsTemplate, 18 | name: 'collections' 19 | }) 20 | 21 | } 22 | 23 | render(node) { 24 | super.render(node) 25 | 26 | } 27 | renderComponents(node) { 28 | super.renderComponents(node) 29 | const info = collectionsService.getInfo() 30 | 31 | const wrapper = N.get('.collections__wrapper', node) 32 | wrapper.style.color = info.c 33 | wrapper.style.backgroundColor = info.bg 34 | 35 | 36 | let navn = N.get('.nav__title__name', node) 37 | navn.innerHTML = info.name 38 | 39 | let navf = N.get('.nav__title__flavour', node) 40 | navf.innerHTML = info.flavour 41 | 42 | let bP = N.get('.total__page__wrapper') 43 | bP.innerHTML = '' 44 | let totalPage = N.Cr('div'), 45 | bufferTotalPage = N.Cr('div') 46 | totalPage.classList.add('total__page') 47 | bufferTotalPage.classList.add('total__page__buffer') 48 | 49 | const l = collectionsService.collectionsInfo.length 50 | totalPage.innerHTML = l > 9 ? l : '0' + l 51 | stringLetterToDoubleSpan(totalPage, 'tooltip__span') 52 | bufferTotalPage.innerHTML = totalPage.innerHTML 53 | 54 | bP.appendChild(totalPage) 55 | bP.appendChild(bufferTotalPage) 56 | 57 | bP.style.color = info.c 58 | let current__page = N.get('.current__page') 59 | current__page.innerHTML = info.index 60 | for (const q of N.getAll('span span', current__page)) { 61 | N.T(q, 0, 0) 62 | } 63 | 64 | this.addEventListener() 65 | } 66 | addEventListener() { 67 | let display = N.get('.display__container') 68 | 69 | display.addEventListener('mouseenter', _ => { 70 | new homeFixation().play() 71 | }) 72 | display.addEventListener('mouseleave', _ => { 73 | new homeFixation(true).play() 74 | }) 75 | } 76 | 77 | onMouseMove(e) { 78 | this.components['ressort-button'].forEach(c => { 79 | c.onMouseMove(e) 80 | }) 81 | } 82 | onMouseUp(e) { 83 | this.components['ressort-button'].forEach(c => { 84 | c.onMouseUp(e) 85 | }) 86 | } 87 | 88 | } 89 | -------------------------------------------------------------------------------- /src/Pages/Collections/collections.scss: -------------------------------------------------------------------------------- 1 | @use '../../styles/utils/responsive.scss' as *; 2 | 3 | $text-color: #E5DFDF; 4 | $background-color: #171717; 5 | [data-template=collections] { 6 | ressort-button { 7 | z-index: 5; 8 | transition: color 1s; 9 | > button { 10 | transition: background-color 1s; 11 | } 12 | } 13 | 14 | grid-fixation { 15 | z-index: 1; 16 | top: unset; 17 | bottom: calc(35px + 30rem); 18 | .fixation { 19 | transition: background-color 1s; 20 | } 21 | } 22 | 23 | } 24 | 25 | .collections__wrapper { 26 | height: 100%; 27 | width: 100%; 28 | } 29 | 30 | .buffer__background { 31 | height: 100%; 32 | width: 100%; 33 | position: absolute; 34 | opacity: 0.0; 35 | z-index: 0; 36 | } 37 | 38 | .back__button__wrapper { 39 | position: absolute; 40 | right: 3rem; 41 | bottom: 2rem; 42 | display: flex; 43 | align-items: center; 44 | z-index: 5; 45 | 46 | .back__tooltip { 47 | font-weight: 700; 48 | font-size: 40px; 49 | line-height: 37px; 50 | /* identical to box height */ 51 | text-transform: uppercase; 52 | margin-right: 1rem; 53 | 54 | span span { 55 | transform: translateX(-103%); 56 | } 57 | } 58 | ressort-button.r_br{ 59 | } 60 | } 61 | 62 | .display__wrapper { 63 | z-index: 2; 64 | display: flex; 65 | top: 91px; 66 | position: absolute; 67 | left: 50%; 68 | transform: translate(-50%); 69 | height: 700px; 70 | flex-direction: column; 71 | } 72 | 73 | .nav__wrapper { 74 | display: flex; 75 | justify-content: center; 76 | align-items: center; 77 | } 78 | 79 | .nav__title__wrapper { 80 | 81 | position: absolute; 82 | right: 0; 83 | text-transform: uppercase; 84 | margin-bottom: -.5rem; 85 | > div { 86 | position: absolute; 87 | transform: translate(-100%, -50%); 88 | @include respond-to(' div { 95 | display: flex; 96 | } 97 | .doublespan__container { 98 | margin-bottom: unset; 99 | } 100 | } 101 | 102 | 103 | } 104 | .nav__title__flavour { 105 | font-size: 2rem; 106 | font-weight: 200; 107 | } 108 | .nav__title__name { 109 | font-size: 3rem; 110 | } 111 | 112 | .buffer__title { 113 | opacity: 0; 114 | 115 | span span { 116 | transform: translateX(-100%); 117 | } 118 | } 119 | 120 | .display__container { 121 | position:relative; 122 | max-width: calc(100vw - 17rem); 123 | margin-top: 2.75rem; 124 | height: 37.5rem; 125 | width: 75rem; 126 | display: flex; 127 | flex-wrap: nowrap; 128 | 129 | a { 130 | position: absolute; 131 | height: 100%; 132 | width: 100%; 133 | } 134 | img { 135 | height: 100%; 136 | width: 50%; 137 | object-fit: cover; 138 | } 139 | 140 | } 141 | @media screen and (max-height: 770px) { 142 | .display__container { 143 | img { 144 | height: calc(70vh - 5rem); 145 | } 146 | } 147 | 148 | } 149 | 150 | @media screen and (min-height: 1000px) { 151 | .display__container { 152 | img { 153 | height: 70vh; 154 | } 155 | } 156 | 157 | } 158 | 159 | .nav__page__wrapper { 160 | position: absolute; 161 | left: 0; 162 | display: flex; 163 | font-size: 3rem; 164 | .total__page, .buffer__page, .current__page, .total__page__buffer { 165 | display: flex; 166 | align-items: center; 167 | } 168 | .buffer__page, .total__page__buffer { 169 | position: absolute; 170 | span span{ 171 | transform: translateX(100%); 172 | } 173 | } 174 | .current__page__wrapper { 175 | display: flex; 176 | width: 3.5rem; 177 | } 178 | 179 | .total__page, .total__page__buffer { 180 | right: 0; 181 | } 182 | .total__page__wrapper { 183 | display: flex; 184 | align-items: center; 185 | transition: color 1s; 186 | &::before { 187 | content: ''; 188 | width: 2rem; 189 | height: 2px; 190 | background-color: currentColor; 191 | transition: background-color 1s; 192 | margin: 0 2rem; 193 | margin-bottom: -1px; 194 | } 195 | } 196 | } 197 | 198 | @media screen and (max-width: 1100px){ 199 | .total__page__wrapper { 200 | opacity: 0; 201 | } 202 | 203 | } 204 | -------------------------------------------------------------------------------- /src/Pages/Contact/contact.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 5 | Contact 6 |
7 | contact_1 8 | 9 |
10 | 28 | 29 |
30 | 31 |
32 | Back 33 |
34 | 35 |
36 | 37 |
38 |
39 |
40 | -------------------------------------------------------------------------------- /src/Pages/Contact/contact.js: -------------------------------------------------------------------------------- 1 | import ContactAnimation, { contactService } from "../../animation/contactAnimation"; 2 | import homeFixation from "../../animation/homeFixation"; 3 | import { canvas } from "../../Canvas/canvas"; 4 | import Page from "../../classes/Page"; 5 | import gridFixation from "../../components/gridFixation/gridFixation"; 6 | import ressortButton from "../../components/ressortButton/ressortButton"; 7 | import { N } from "../../utils/namhai"; 8 | import contactTemplate from './contact.html?raw' 9 | 10 | 11 | export default class Contact extends Page { 12 | constructor() { 13 | super({ 14 | components: { 15 | 'grid-fixation': gridFixation, 16 | 'ressort-button': ressortButton 17 | }, 18 | content: contactTemplate, 19 | name: 'contact' 20 | }) 21 | 22 | N.BM(this, ['addClickEvent']) 23 | this.tl = new N.TL 24 | this.iRaf = new N.RafR(_ => { 25 | if (canvas.contact && !canvas.contact.init) return 26 | this.addClickEvent() 27 | this.iRaf.stop() 28 | this.iRaf = null 29 | }) 30 | } 31 | 32 | render(node) { 33 | super.render(node) 34 | 35 | } 36 | 37 | renderComponents(node) { 38 | super.renderComponents(node) 39 | 40 | this.imageWrapper = N.get('.contact__container img', node) 41 | this.linksWrapper = N.get('.contact__links', node) 42 | this.bgBuffer = N.get('.contact__bg__buffer', node) 43 | this.wrapper = N.get('.contact__wrapper', node) 44 | this.wrapper.style.color = contactService.getInfo().c 45 | this.wrapper.style.backgroundColor = contactService.getInfo().bg 46 | this.bgBuffer.style.color = contactService.getNextInfo().c 47 | this.bgBuffer.style.backgroundColor = contactService.getNextInfo().bg 48 | this.contactTitle = N.get('.contact__title') 49 | this.contactTitleSpans = N.getAll('span span', this.contactTitle); 50 | this.linkSpans = N.getAll('span span', this.linksWrapper) 51 | 52 | this.backButton = N.get('.back__button__wrapper', node) 53 | this.fixation = N.get('grid-fixation', node) 54 | 55 | this.addEventListener() 56 | 57 | this.iRaf.run() 58 | } 59 | 60 | addClickEvent() { 61 | this.clickBool = false 62 | 63 | this.imageWrapper.addEventListener('click', async _ => { 64 | if (this.clickBool) return 65 | this.clickBool = true 66 | this.imageWrapper.classList.add('d-cursor') 67 | await new Promise(s => { 68 | 69 | const cA = new ContactAnimation(s, this.wrapper, this.bgBuffer, this.contactTitle, this.contactTitleSpans, this.linkSpans, this.linksWrapper, this.backButton, this.fixation) 70 | cA.play() 71 | }) 72 | this.imageWrapper.classList.remove('d-cursor') 73 | this.clickBool = false 74 | }) 75 | } 76 | addEventListener() { 77 | 78 | Object.values([this.linksWrapper, this.imageWrapper]).forEach(a => { 79 | 80 | a.addEventListener('mouseenter', _ => { 81 | new homeFixation().play() 82 | }) 83 | a.addEventListener('mouseleave', _ => { 84 | new homeFixation(true).play() 85 | }) 86 | }) 87 | } 88 | onMouseMove(e) { 89 | this.components['ressort-button'].forEach(c => { 90 | c.onMouseMove(e) 91 | }) 92 | } 93 | onMouseUp(e) { 94 | this.components['ressort-button'].forEach(c => { 95 | c.onMouseUp(e) 96 | }) 97 | } 98 | 99 | hide() { 100 | if (this.iRaf) this.iRaf.stop() 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/Pages/Contact/contact.scss: -------------------------------------------------------------------------------- 1 | [data-template=contact] { 2 | grid-fixation { 3 | z-index: 1; 4 | top: unset; 5 | bottom: calc(35px + 30rem); 6 | transition: color 400ms; 7 | transition-timing-function: cubic-bezier(1, 0.01, 1, 1); 8 | .fixation { 9 | transition: background-color 450ms; 10 | transition-timing-function: cubic-bezier(1, 0.01, 1, 1); 11 | } 12 | } 13 | 14 | .back__button__wrapper { 15 | transition: color 400ms; 16 | transition-timing-function: cubic-bezier(1, 0.01, 1, 1); 17 | } 18 | } 19 | .contact__wrapper { 20 | color: #DF7863; 21 | background: #BD513A; 22 | height: 100%; 23 | width: 100%; 24 | } 25 | 26 | .contact__bg__buffer { 27 | position: absolute; 28 | height: 100%; 29 | width: 100%; 30 | background-color: #2B2454; 31 | color: #372F67; 32 | opacity: 0; 33 | } 34 | 35 | .contact__container { 36 | z-index: 2; 37 | position: absolute; 38 | top: 50%; 39 | left: 50%; 40 | transform: translate(-50%, -50%); 41 | } 42 | 43 | .contact__title { 44 | position: absolute; 45 | top: -65px; 46 | left: -13rem; 47 | width: 80rem; 48 | font-weight: 400; 49 | font-size: 128px; 50 | text-transform: uppercase; 51 | pointer-events: none; 52 | 53 | >span { 54 | padding-right: 0.68em; 55 | } 56 | } 57 | 58 | .contact__container img{ 59 | position: relative; 60 | // height: 465px; 61 | width: 939px; 62 | max-width: 90vw; 63 | aspect-ratio: 939 / 465; 64 | display: block; 65 | cursor: pointer; 66 | 67 | &.d-cursor { 68 | cursor: default; 69 | } 70 | } 71 | 72 | .contact__links { 73 | display: flex; 74 | flex-direction: column; 75 | position: absolute; 76 | font-size: 36px; 77 | text-transform: uppercase; 78 | z-index: 1; 79 | font-weight: 400; 80 | top: 2rem; 81 | right: 3rem; 82 | text-align: end; 83 | width: 13rem; 84 | 85 | a svg { 86 | height: 36px; 87 | position: absolute; 88 | left: 0; 89 | opacity: 0; 90 | transform: translateX(2rem); 91 | 92 | transition: opacity 300ms, transform 300ms; 93 | } 94 | 95 | a:hover svg { 96 | opacity: 1; 97 | transform: translateX(0rem); 98 | 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/Pages/Demo/demo.html: -------------------------------------------------------------------------------- 1 |
2 | 00 3 | 4 |
5 | 6 | 7 |
8 | 11 |
12 | T 13 | R 14 | Y 15 |   16 | T 17 | O 18 |   19 | D 20 | R 21 | A 22 | G 23 |   24 |
25 | T 26 | H 27 | I 28 | N 29 | G 30 | S 31 |   32 | A 33 | R 34 | O 35 | U 36 | N 37 | D 38 |
39 | 40 |
41 | L 42 | I 43 | K 44 | 45 | E 46 |   47 | T 48 | H 49 | I 50 | S 51 | , 52 |   53 | Y 54 | E 55 | S 56 |
57 |
58 |
59 |
60 | -------------------------------------------------------------------------------- /src/Pages/Demo/demo.js: -------------------------------------------------------------------------------- 1 | import Page from "../../classes/Page" 2 | import ressortButton from "../../components/ressortButton/ressortButton" 3 | import demoTemplate from "./demo.html?raw" 4 | import { N } from "../../utils/namhai"; 5 | 6 | export default class Demo extends Page { 7 | constructor() { 8 | 9 | super({ 10 | components: { 11 | 'ressort-button': ressortButton 12 | }, 13 | content: demoTemplate, 14 | name: 'demo' 15 | }) 16 | 17 | } 18 | 19 | render(node) { 20 | super.render(node) 21 | 22 | } 23 | 24 | renderComponents(node) { 25 | super.renderComponents(node) 26 | } 27 | 28 | onMouseMove(e) { 29 | this.components['ressort-button'].forEach(c => { 30 | c.onMouseMove(e) 31 | }) 32 | } 33 | onMouseUp(e) { 34 | this.components['ressort-button'].forEach(c => { 35 | c.onMouseUp(e) 36 | }) 37 | } 38 | 39 | async hide() { 40 | this.ressort = this.components['ressort-button'][0] 41 | await new Promise(res => { 42 | let raf = new N.RafR(() => { 43 | if (this.ressort.end) { 44 | res() 45 | raf.stop() 46 | } 47 | }) 48 | raf.run() 49 | }) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/Pages/Demo/demo.scss: -------------------------------------------------------------------------------- 1 | [data-template=demo] { 2 | } 3 | .demo__wrapper { 4 | -webkit-touch-callout: none; /* iOS Safari */ 5 | -webkit-user-select: none; /* Safari */ 6 | -khtml-user-select: none; /* Konqueror HTML */ 7 | -moz-user-select: none; /* Old versions of Firefox */ 8 | -ms-user-select: none; /* Internet Explorer/Edge */ 9 | user-select: none; /* Non-prefixed version, currently*/ 10 | 11 | color: white; 12 | 13 | height: 100%; 14 | display: flex; 15 | justify-content: center; 16 | align-items: center; 17 | 18 | .doublespan__container { 19 | margin-inline: -5px; 20 | } 21 | 22 | 23 | ressort-button button { 24 | // transition: transform 200ms; 25 | transition: box-shadow 500ms; 26 | box-shadow: 0 0 0px 0 white; 27 | 28 | } 29 | ressort-button button:hover { 30 | box-shadow: 0 0 23px -2px white; 31 | } 32 | } 33 | 34 | .demo__number { 35 | font-size: 900px; 36 | 37 | display: block; 38 | line-height: 100%; 39 | left: 0; 40 | display: none; 41 | position: absolute; 42 | 43 | } 44 | 45 | .ressort__demo__wrapper{ 46 | display: flex; 47 | align-items: center; 48 | width: 7rem; 49 | position: relative; 50 | 51 | ressort-button { 52 | height: 7rem; 53 | width: 7rem; 54 | border-radius: 5px; 55 | } 56 | 57 | 58 | } 59 | .ressort__demo__tooltip__wrapper { 60 | width: 315px; 61 | position: absolute; 62 | left: 9rem; 63 | font-size: 40px; 64 | line-height: 37px; 65 | 66 | > div { 67 | transform: translateY(-50%); 68 | position: absolute; 69 | span span { 70 | transform: translateX(105%); 71 | } 72 | } 73 | } 74 | 75 | -------------------------------------------------------------------------------- /src/Pages/Details/detail.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 | 6 |
7 |
8 | 9 | 10 |
11 | 12 |
13 | -------------------------------------------------------------------------------- /src/Pages/Details/detail.js: -------------------------------------------------------------------------------- 1 | import { collectionsService } from "../../animation/collectionsAnimationService"; 2 | import { fixationState } from "../../animation/homeFixation"; 3 | import Page from "../../classes/Page"; 4 | import { N } from "../../utils/namhai"; 5 | import detailTemplate from './detail.html?raw' 6 | 7 | export default class Detail extends Page { 8 | constructor() { 9 | super({ 10 | content: detailTemplate, 11 | name: 'detail' 12 | }) 13 | 14 | } 15 | 16 | renderComponents(node) { 17 | super.renderComponents(node) 18 | fixationState[0] = true 19 | const cInfo = collectionsService.getInfo() 20 | this.d = N.get('.detail__wrapper') 21 | const p = N.get('.p__container', node) 22 | p.innerHTML = cInfo.detailHTML 23 | this.d.style.setProperty('--bg-color', cInfo.bg) 24 | this.d.style.setProperty('--main-color', cInfo.c) 25 | 26 | const titleFlavour = N.get('.nav__title__flavour', node) 27 | const titleName = N.get('.nav__title__name', node) 28 | titleFlavour.innerText = cInfo.dF 29 | titleName.innerText = cInfo.dN 30 | 31 | const images = N.getAll('img', p) 32 | Object.values(images).forEach(img => { 33 | img.style.transform = 'scale(1.1)' 34 | img.onload = _ => { 35 | N.O(img, 1) 36 | } 37 | 38 | const fullSizedImage = new Image() 39 | fullSizedImage.src = 'detail' + img.getAttribute('src').slice(15) 40 | N.O(fullSizedImage, 1) 41 | fullSizedImage.alt = img.getAttribute('alt') 42 | fullSizedImage.style.transform = 'scale(1.1)' 43 | fullSizedImage.onload = _ => { 44 | // img.src = fullSizedImage.src 45 | 46 | img.replaceWith(fullSizedImage) 47 | setTimeout(_ => { 48 | fullSizedImage.style.transform = 'scale(1)' 49 | }, 20) 50 | } 51 | }) 52 | this.addEventListener() 53 | } 54 | addEventListener() { 55 | this.d.addEventListener('scroll', this.onScroll.bind(this)) 56 | } 57 | 58 | onScroll(e) { 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/Pages/Details/detail.scss: -------------------------------------------------------------------------------- 1 | .detail__wrapper { 2 | --bg-color: blue; 3 | --main-color: red; 4 | text-transform: uppercase; 5 | height: 100%; 6 | width: 100%; 7 | background-color: var(--bg-color); 8 | color: var(--main-color); 9 | overflow-y: scroll; 10 | scrollbar-color: currentColor; 11 | scrollbar-width: thin; 12 | & { 13 | scrollbar-width: thin; 14 | scrollbar-color: currentColor var(--bg-color); 15 | } 16 | 17 | &::-webkit-scrollbar { 18 | width: 12px; 19 | } 20 | 21 | &::-webkit-scrollbar-track { 22 | background: var(--bg-color); 23 | } 24 | 25 | &::-webkit-scrollbar-thumb { 26 | background-color: currentColor; 27 | border-radius: 20px; 28 | border: 3px solid var(--bg-color); 29 | } 30 | 31 | .nav__title__flavour { 32 | font-size: 3rem; 33 | } 34 | .nav__title__name { 35 | font-size: 4rem; 36 | } 37 | } 38 | 39 | .back__wrapper { 40 | position: absolute; 41 | bottom: 3rem; 42 | right: calc(6.5rem + 12px); 43 | font-size: 3rem; 44 | } 45 | 46 | .title__wrapper { 47 | position: absolute; 48 | top: 3rem; 49 | right: calc(6.5rem + 12px); 50 | } 51 | 52 | .detail__container { 53 | display: flex; 54 | flex-direction: row; 55 | justify-content: space-between; 56 | padding: 3rem 6.5rem; 57 | } 58 | 59 | .p__container { 60 | display: grid; 61 | width: 100%; 62 | grid-template-columns: repeat(6, 1fr); 63 | row-gap: 1rem; 64 | .detail__img__container { 65 | grid-column: 1/3; 66 | width: 100%; 67 | background-color: var(--main-color); 68 | 69 | overflow: hidden; 70 | display: flex; 71 | } 72 | img { 73 | width: 100%; 74 | opacity: 0; 75 | transition: opacity 300ms, transform 300ms; 76 | object-fit: cover; 77 | } 78 | 79 | .cI { 80 | grid-column: 1/4; 81 | } 82 | .gI { 83 | grid-column: 1/5; 84 | } 85 | .ggI { 86 | grid-column: 1/6; 87 | } 88 | } 89 | 90 | @media screen and (max-width: 1200px) { 91 | .p__container { 92 | img { 93 | grid-column: 1/4; 94 | width: 100%; 95 | } 96 | .gI { 97 | grid-column: 1/6; 98 | } 99 | } 100 | } 101 | @media screen and (max-width: 900px) { 102 | .p__container { 103 | img { 104 | grid-column: 1/7; 105 | width: 100%; 106 | } 107 | .gI { 108 | grid-column: 1/7; 109 | } 110 | } 111 | 112 | .back__wrapper { 113 | transform-origin: right; 114 | transform: rotate(90deg) translate(26px, -25px); 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /src/Pages/Home/home.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 6 |
7 | 8 | 9 | NAM HAI 10 |
11 | 12 |
13 |
14 | WebGL 15 | home1 16 | freelance 17 | home2 18 |
19 |
20 | creative 21 | Performance 22 | home3 23 | design 24 |
25 |
26 | creative 27 | home4 28 | developer 29 |
30 |
31 | 32 |
33 |
34 |
35 | Inspiration 36 |
37 |
38 | Contact 39 |
40 |
41 | 42 |
43 |
44 | -------------------------------------------------------------------------------- /src/Pages/Home/home.js: -------------------------------------------------------------------------------- 1 | import homeFixation from "../../animation/homeFixation"; 2 | import Page from "../../classes/Page"; 3 | import gridFixation from "../../components/gridFixation/gridFixation"; 4 | import ressortButton from "../../components/ressortButton/ressortButton"; 5 | import { N } from "../../utils/namhai"; 6 | import { stringLetterToDoubleSpan } from "../../utils/utilsText"; 7 | import homeTemplate from "./home.html?raw" 8 | 9 | export default class Home extends Page { 10 | constructor() { 11 | super({ 12 | components: { 13 | 'grid-fixation': gridFixation, 14 | 'ressort-button': ressortButton 15 | }, 16 | content: homeTemplate, 17 | name: 'home' 18 | }) 19 | this.currentState = 0 20 | 21 | N.BM(this, ['addEventListener']) 22 | } 23 | onMouseMove(e) { 24 | this.components['ressort-button'].forEach(c => { 25 | c.onMouseMove(e) 26 | }) 27 | } 28 | onMouseUp(e) { 29 | this.components['ressort-button'].forEach(c => { 30 | c.onMouseUp(e) 31 | }) 32 | } 33 | 34 | render(node) { 35 | super.render(node) 36 | 37 | let htI = N.get('.htI', node) 38 | stringLetterToDoubleSpan(htI, 'tooltip__span') 39 | let htC = N.get('.htC', node) 40 | stringLetterToDoubleSpan(htC, 'tooltip__span') 41 | 42 | } 43 | 44 | renderComponents(node) { 45 | super.renderComponents(node) 46 | this.hero = N.get('.hero img', node) 47 | } 48 | 49 | addEventListener() { 50 | this.hero.addEventListener('mouseenter', _ => { 51 | new homeFixation().play() 52 | }) 53 | this.hero.addEventListener('mouseleave', _ => { 54 | new homeFixation(true).play() 55 | }) 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/Pages/Home/home.scss: -------------------------------------------------------------------------------- 1 | @use '../../styles/utils/variables.scss' as *; 2 | [data-template=home] { 3 | background-color: white; 4 | 5 | grid-fixation { 6 | color: black; 7 | } 8 | ressort-button { 9 | 10 | position: absolute; 11 | z-index: 5; 12 | width: 2.5rem; 13 | height: 2.5rem; 14 | } 15 | ressort-button.c_w { 16 | position: relative; 17 | } 18 | } 19 | 20 | .home__wrapper { 21 | position: absolute; 22 | height: 100%; 23 | width: 100%; 24 | background-color: white; 25 | } 26 | .home__action__wrapper{ 27 | bottom: 50px; 28 | left: 50%; 29 | transform: translateX(-50%); 30 | position: absolute; 31 | display: flex; 32 | flex-direction: column; 33 | align-items: center; 34 | } 35 | .home__action__tooltip{ 36 | font-style: normal; 37 | font-weight: 700; 38 | font-size: 40px; 39 | line-height: 37px; 40 | text-transform: uppercase; 41 | 42 | color: black; 43 | } 44 | 45 | .hero { 46 | z-index: 2; 47 | position: absolute; 48 | top: 50%; 49 | left: 50%; 50 | transform: translate(-50%, -50%); 51 | display: flex; 52 | img { 53 | height: 38rem; 54 | width: 38rem; 55 | cursor: pointer; 56 | 57 | &.d-cursor { 58 | cursor: default; 59 | } 60 | } 61 | } 62 | 63 | .background-text { 64 | position: absolute; 65 | width: 187px; 66 | height: 162px; 67 | top: 477px; 68 | right: -3rem; 69 | 70 | font-size: 20px; 71 | line-height: 18px; 72 | text-align: right; 73 | } 74 | 75 | .background__flavour-text { 76 | z-index: 1; 77 | position: absolute; 78 | width: 187px; 79 | height: 264px; 80 | top: calc(50% + 16rem); 81 | transform: translate(calc(-50% - 17rem),-50%); 82 | left: 50%; 83 | 84 | font-size: 24px; 85 | line-height: 22px; 86 | text-transform: uppercase; 87 | } 88 | 89 | .background__title { 90 | position: absolute; 91 | width: max-content; 92 | height: 270px; 93 | // top: 296px; 94 | top: calc(100% - 700px); 95 | left: 50%; 96 | transform: translateX(-50%); 97 | font-size: 370px; 98 | line-height: 73%; 99 | letter-spacing: -0.005em; 100 | } 101 | 102 | .home__text__wrapper { 103 | display: flex; 104 | flex-direction: column; 105 | position: absolute; 106 | width: 90%; 107 | height: 274px; 108 | left: 50%; 109 | transform: translateX(-50%); 110 | // top: 566px; 111 | top: calc(100% - 420px); 112 | 113 | > div { 114 | font-size: 96px; 115 | line-height: 88px; 116 | text-transform: uppercase; 117 | display: flex; 118 | flex-wrap: nowrap; 119 | column-gap: 1rem; 120 | >span { 121 | flex-shrink: 0; 122 | } 123 | img { 124 | height: 68px; 125 | width: 0; 126 | object-fit: cover; 127 | border-radius: 34px; 128 | } 129 | } 130 | } 131 | .nrd{ 132 | display: none; 133 | } 134 | @media screen and (max-width: 1300px) { 135 | .rd { 136 | display: none; 137 | } 138 | 139 | .nrd { 140 | display: block; 141 | } 142 | 143 | .fd { 144 | flex-direction: row-reverse; 145 | } 146 | } 147 | 148 | .grow-1 { 149 | flex-grow: 1; 150 | } 151 | .grow-2 { 152 | flex-grow: 2; 153 | } 154 | .grow-3 { 155 | flex-grow: 3; 156 | } 157 | .singlespan__container { 158 | display: inline-block 159 | } 160 | 161 | .home__action__tooltip__wrapper { 162 | pointer-events: none; 163 | user-select: none; /* supported by Chrome and Opera */ 164 | -webkit-user-select: none; /* Safari */ 165 | -khtml-user-select: none; /* Konqueror HTML */ 166 | -moz-user-select: none; /* Firefox */ 167 | -ms-user-select: none; /* Internet Explorer/Edge */ 168 | height: 37px; 169 | margin-bottom: .5rem; 170 | } 171 | .home__action__tooltip { 172 | position: absolute; 173 | display: flex; 174 | transform: translateX(-50%); 175 | .doublespan__container { 176 | margin-bottom: unset; 177 | } 178 | span span { 179 | transform: translateX(-100%); 180 | } 181 | } 182 | -------------------------------------------------------------------------------- /src/Pages/Preloader/preloader.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 00 5 |
6 | -------------------------------------------------------------------------------- /src/Pages/Preloader/preloader.js: -------------------------------------------------------------------------------- 1 | import Page from "../../classes/Page" 2 | import preloaderTemplate from "./preloader.html?raw" 3 | 4 | export default class Preloader extends Page { 5 | constructor() { 6 | 7 | super({ 8 | content: preloaderTemplate, 9 | name: 'preloader' 10 | }) 11 | } 12 | 13 | render(node) { 14 | super.render(node) 15 | this.content.remove() 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/Pages/Preloader/preloader.scss: -------------------------------------------------------------------------------- 1 | [data-template=preloader] { 2 | background-color: black; 3 | color: white; 4 | } 5 | 6 | .preloader__bar { 7 | position: relative; 8 | height: 0.5rem; 9 | background-color: white; 10 | width: 100%; 11 | left: -200%; 12 | transform: scaleX(0%); 13 | transition: transform 200ms; 14 | transform-origin: 0%; 15 | } 16 | .preloader__counter { 17 | font-size: 1100px; 18 | display: flex; 19 | position: absolute; 20 | } 21 | -------------------------------------------------------------------------------- /src/Pages/page.scss: -------------------------------------------------------------------------------- 1 | @forward './Preloader/preloader.scss'; 2 | @forward './Demo/demo.scss'; 3 | @forward './Home/home.scss'; 4 | @forward './Collections/collections.scss'; 5 | @forward './Contact/contact.scss'; 6 | @forward './Details/detail.scss'; 7 | -------------------------------------------------------------------------------- /src/animation/TransitionCollectionsHome.js: -------------------------------------------------------------------------------- 1 | import { N } from "../utils/namhai"; 2 | 3 | export default class TransitionCollectionsHome { 4 | constructor({ cb, canvas, oldRoute, route }) { 5 | this.tl = new N.TL 6 | const m = N.get('.main'), 7 | mB = N.get('.buffer-main') 8 | 9 | mB.classList.add('buffer-main__DOWN') 10 | canvas.onChange('home') 11 | 12 | const collectionsMedias = canvas.collections.medias, 13 | boundsY = collectionsMedias[0].boundsPixel 14 | 15 | this.tl.from({ 16 | d: 1000, 17 | e: 'io6', 18 | update: t => { 19 | N.T(m, 0, -t.progE * 100) 20 | N.T(mB, 0, -t.progE * 100) 21 | canvas.collections.group.position.y = canvas.size.height * t.progE 22 | }, 23 | cb: _ => { 24 | canvas.hide(oldRoute) 25 | cb() 26 | } 27 | }) 28 | } 29 | play() { 30 | this.tl.play() 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/animation/TransitionContactHome.js: -------------------------------------------------------------------------------- 1 | import { N } from "../utils/namhai"; 2 | 3 | export default class TransitionContactHome { 4 | constructor({ cb, canvas, oldRoute, route }) { 5 | this.tl = new N.TL 6 | const m = N.get('.main'), 7 | mB = N.get('.buffer-main') 8 | 9 | mB.classList.add('buffer-main__DOWN') 10 | canvas.onChange('home') 11 | 12 | const contact = canvas.contact, 13 | boundsY = contact.heroBoundsPixel 14 | 15 | this.tl.from({ 16 | d: 1000, 17 | e: 'io6', 18 | update: t => { 19 | N.T(m, 0, -t.progE * 100) 20 | N.T(mB, 0, -t.progE * 100) 21 | canvas.contact.group.position.y = canvas.size.height * t.progE 22 | }, 23 | cb: _ => { 24 | canvas.hide(oldRoute) 25 | cb() 26 | } 27 | }) 28 | } 29 | play() { 30 | this.tl.play() 31 | } 32 | } 33 | 34 | -------------------------------------------------------------------------------- /src/animation/TransitionDemoHome.js: -------------------------------------------------------------------------------- 1 | import { N } from "../utils/namhai"; 2 | 3 | export default class TransitionDemoHome { 4 | constructor({ r, cb, canvas, oldRoute, route }) { 5 | 6 | const mB = N.get('.buffer-main'), 7 | homeWB = N.get('.home__wrapper', mB), 8 | lineTextHome = N.getAll('.home__text', homeWB) 9 | mB.classList.add('buffer-main__cover') 10 | N.O(mB, 0) 11 | N.O(homeWB, 0) 12 | this.tl = new N.TL 13 | this.r = r 14 | 15 | const mesh = canvas.demo.mesh, 16 | initX = mesh.scale.x, 17 | initY = mesh.scale.y, 18 | targetX = canvas.size.width, 19 | targetY = canvas.size.height; 20 | canvas.demo.program.uniforms.o.value = 1 21 | 22 | this.tl.from({ 23 | d: 1000, 24 | e: 'o6', 25 | update: t => { 26 | mesh.scale.x = N.Lerp(initX, targetX, t.progE) 27 | mesh.scale.y = N.Lerp(initY, targetY, t.progE) 28 | 29 | canvas.demo.program.uniforms.radius.value = Math.max(canvas.demo.buttonBounds.width, canvas.demo.buttonBounds.height) * 4 30 | canvas.demo.program.uniforms.force.value = N.Lerp(-3.5, 0, N.Ease.o3(t.prog)) 31 | }, 32 | cb: _ => { 33 | canvas.onChange(route) 34 | canvas.demo.program.uniforms.o.value = 0 35 | canvas.hide(oldRoute) 36 | N.O(mB, 1) 37 | } 38 | }) 39 | this.tl.from({ 40 | delay: 500, 41 | d: 1000, 42 | el: homeWB, 43 | p: { 44 | o: [0, 1] 45 | }, 46 | cb: _ => cb() 47 | }) 48 | Object.entries(lineTextHome).forEach(([i, el]) => { 49 | this.tl.from({ 50 | delay: 700, 51 | d: 1000, 52 | el: el, 53 | p: { 54 | x: [-100 * ((i % 2) * 2 - 1), 0] 55 | }, 56 | e: 'io5' 57 | }) 58 | }) 59 | } 60 | 61 | play() { 62 | this.tl.play() 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/animation/TransitionDetailCollections.js: -------------------------------------------------------------------------------- 1 | import { N } from "../utils/namhai"; 2 | import { Texture, Program, Plane, Mesh } from 'ogl' 3 | import BasicFrag from './shaders/BasicFrag.glsl?raw' 4 | import WhiteFrag from './shaders/WhiteFrag.glsl?raw' 5 | import BasicVer from './shaders/BasicVer.glsl?raw' 6 | 7 | export default class TransitionHomeCollections { 8 | constructor({ cb, canvas, oldRoute, route, pageBufferContent }) { 9 | 10 | let detailWrapper = N.get('.detail__wrapper') 11 | // let bgColor = getComputedStyle(detailWrapper).getPropertyValue('--bg-color') 12 | // detailWrapper.style.setProperty('--bg-color', bgColor + '00') 13 | 14 | this.gl = canvas.gl 15 | this.tl = new N.TL() 16 | 17 | 18 | this.canvas = canvas 19 | 20 | let program = new Program(this.gl, { 21 | fragment: BasicFrag, 22 | vertex: BasicVer, 23 | uniforms: { 24 | resolution: { 25 | value: [this.canvas.size.width, this.canvas.size.height] 26 | }, 27 | tMap: { 28 | value: new Texture(this.gl) 29 | }, 30 | f: { 31 | value: 0 32 | } 33 | } 34 | }) 35 | 36 | let whiteMesh = new Mesh(this.gl, { 37 | geometry: new Plane(this.gl, { 38 | heightSegments: 50, 39 | widthSegments: 50 40 | }), 41 | program: new Program(this.gl, { 42 | fragment: WhiteFrag, 43 | vertex: BasicVer, 44 | uniforms: { 45 | resolution: { 46 | value: [this.canvas.size.width, this.canvas.size.height] 47 | }, 48 | f: { 49 | value: 0 50 | } 51 | } 52 | }) 53 | }) 54 | 55 | let mesh = new Mesh(this.gl, { 56 | geometry: new Plane(this.gl, { 57 | heightSegments: 50, 58 | widthSegments: 50 59 | }), 60 | program 61 | }) 62 | 63 | const borderWidth = 1.07 64 | mesh.scale.x = this.canvas.size.width * (1) 65 | mesh.scale.y = this.canvas.size.height * (1) 66 | whiteMesh.scale.x = this.canvas.size.width * borderWidth 67 | whiteMesh.scale.y = this.canvas.size.height * borderWidth 68 | whiteMesh.position.z = -0.1 69 | html2canvas(N.get('.main')).then((canvas) => { 70 | const base64image = canvas.toDataURL("image/png"); 71 | let image = new window.Image() 72 | image.src = base64image 73 | let texture = new Texture(this.gl) 74 | image.onload = async c => { 75 | texture.image = image 76 | mesh.program.uniforms.tMap.value = texture 77 | 78 | pageBufferContent.classList.add('buffer-main__cover') 79 | this.canvas.collections.getBounds() 80 | this.canvas.onChange('collections') 81 | 82 | 83 | this.canvas.collections.init() 84 | // this.canvas.hide(oldRoute) 85 | whiteMesh.setParent(this.canvas.scene) 86 | mesh.setParent(this.canvas.scene) 87 | this.tl.from({ 88 | d: 1000, 89 | e: 'io3', 90 | update: t => { 91 | whiteMesh.scale.x = this.canvas.size.width * borderWidth * (1 - t.progE) 92 | whiteMesh.scale.y = this.canvas.size.height * borderWidth * (1 - t.progE) 93 | whiteMesh.position.x = -this.canvas.size.width * (3 / 5) * t.progE 94 | whiteMesh.position.y = this.canvas.size.height * (3 / 5) * t.progE 95 | whiteMesh.program.uniforms.f.value = N.Clamp(t.progE * 2, 0, 1) 96 | 97 | mesh.scale.x = this.canvas.size.width * (1 - t.progE) 98 | mesh.scale.y = this.canvas.size.height * (1 - t.progE) 99 | mesh.position.x = -this.canvas.size.width * (3 / 5) * t.progE 100 | mesh.position.y = this.canvas.size.height * (3 / 5) * t.progE 101 | 102 | mesh.program.uniforms.f.value = N.Clamp(t.progE * 2, 0, 1) 103 | }, 104 | cb: _ => { 105 | this.canvas.scene.removeChild(whiteMesh) 106 | this.canvas.scene.removeChild(mesh) 107 | this.canvas.collections.init() 108 | cb() 109 | } 110 | }) 111 | 112 | this.tl.play() 113 | 114 | } 115 | }); 116 | } 117 | 118 | play() { 119 | } 120 | } 121 | 122 | -------------------------------------------------------------------------------- /src/animation/TransitionHomeCollections.js: -------------------------------------------------------------------------------- 1 | import { N } from "../utils/namhai"; 2 | 3 | export default class TransitionHomeCollections { 4 | constructor({ cb, canvas, oldRoute, route }) { 5 | this.tl = new N.TL 6 | const m = N.get('.main') 7 | const mB = N.get('.buffer-main') 8 | 9 | mB.classList.add('buffer-main__UP') 10 | canvas.onChange('collections') 11 | canvas.collections.init() 12 | const collectionsMedias = canvas.collections.medias 13 | 14 | const boundsY = collectionsMedias[0].boundsPixel 15 | this.tl.from({ 16 | d: 1000, 17 | e: 'io6', 18 | update: (t) => { 19 | 20 | N.T(m, 0, t.progE * 100) 21 | N.T(mB, 0, t.progE * 100) 22 | collectionsMedias.forEach(m => { 23 | m.mesh.position.y = (-boundsY.y + canvas.sizePixel.height / 2) * canvas.size.height / canvas.sizePixel.height - m.bounds.height / 2 24 | m.mesh.position.y -= canvas.size.height * t.progE 25 | }); 26 | }, 27 | cb: _ => { 28 | canvas.hide(oldRoute) 29 | canvas.collections.getBounds() 30 | cb() 31 | } 32 | }) 33 | } 34 | 35 | play() { 36 | this.tl.play() 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/animation/TransitionHomeContact.js: -------------------------------------------------------------------------------- 1 | import { N } from "../utils/namhai"; 2 | 3 | export default class TransitionHomeContact { 4 | constructor({ cb, canvas, oldRoute, route }) { 5 | this.tl = new N.TL 6 | const m = N.get('.main') 7 | const mB = N.get('.buffer-main') 8 | 9 | mB.classList.add('buffer-main__UP') 10 | canvas.onChange('contact') 11 | const contact = canvas.contact 12 | const boundsY = contact.heroBoundsPixel 13 | 14 | this.tl.from({ 15 | d: 1000, 16 | e: 'io6', 17 | update: (t) => { 18 | 19 | N.T(m, 0, t.progE * 100) 20 | N.T(mB, 0, t.progE * 100) 21 | contact.mesh.position.y = (-boundsY.y + canvas.sizePixel.height / 2) * canvas.size.height / canvas.sizePixel.height - contact.heroBounds.height / 2 22 | contact.mesh.position.y -= canvas.size.height * t.progE 23 | }, 24 | cb: _ => { 25 | canvas.hide(oldRoute) 26 | canvas.contact.getBounds() 27 | cb() 28 | } 29 | }) 30 | } 31 | 32 | play() { 33 | this.tl.play() 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/animation/TransitionPreloaderDemo.js: -------------------------------------------------------------------------------- 1 | import { N } from "../utils/namhai"; 2 | 3 | export default class TransitionPreloaderDemo { 4 | constructor({ cb, canvas, oldRoute, route }) { 5 | const button = N.get('ressort-button'), 6 | bFixation = N.get('a > div > svg', button), 7 | size = canvas.sizePixel, 8 | mB = N.get('.buffer-main'), 9 | tooltipSpans = N.getAll('.ressort__demo__tooltip__wrapper span span'), 10 | preloaderBar = N.get('.preloader__bar'); 11 | preloaderBar.style.transition = 'unset' 12 | Object.values(tooltipSpans).map(s => N.T(s, 105, 0)) 13 | mB.classList.add('buffer-main__cover') 14 | N.O(bFixation, 0) 15 | this.tl = new N.TL 16 | 17 | N.T(button, 0, 0.5 * size.height + 3.5 * 16, 'px') 18 | this.tl.from({ 19 | el: preloaderBar, 20 | e: 'i3', 21 | p: { 22 | scaleX: [3, 2] 23 | }, 24 | d: 400, 25 | }) 26 | this.tl.from({ 27 | d: 1000, 28 | el: button, 29 | e: 'io5', 30 | p: { 31 | y: [0.5 * size.height + 3.5 * 16, 0, 'px'] 32 | }, 33 | }) 34 | this.tl.from({ 35 | el: N.getAll('.ressort__demo__tooltip span span'), 36 | d: 450, 37 | e: 'o5', 38 | p: { 39 | x: [105, 0] 40 | }, 41 | delay: 800, 42 | }) 43 | this.tl.from({ 44 | el: bFixation, 45 | d: 500, 46 | e: 'o5', 47 | p: { 48 | rotateZ: [180, 0], 49 | o: [0, 1] 50 | }, 51 | delay: 700, 52 | cb: _ => { 53 | canvas.onChange(route) 54 | canvas.hide(oldRoute) 55 | cb() 56 | } 57 | }) 58 | } 59 | 60 | play() { 61 | this.tl.play() 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /src/animation/collectionsAnimation.js: -------------------------------------------------------------------------------- 1 | import { canvas } from "../Canvas/canvas" 2 | import { N } from "../utils/namhai" 3 | import { stringLetterToDoubleSpan } from "../utils/utilsText" 4 | import { collectionsService } from "./collectionsAnimationService" 5 | 6 | export default class collectionsAnime { 7 | constructor() { 8 | this.button = N.get('.nR button') 9 | this.canvas = canvas 10 | 11 | this.info = collectionsService.getInfo() 12 | 13 | 14 | 15 | this.wrapper = N.get('.collections__wrapper') 16 | N.PE.none(this.wrapper) 17 | 18 | let bB = N.get('.buffer__background') 19 | bB.style.backgroundColor = this.info.bg 20 | this.titleWrapperBuffer = N.get('.buffer__title') 21 | 22 | let navf = N.get('.true__title .nav__title__flavour') 23 | let navn = N.get('.true__title .nav__title__name') 24 | let navTitleNameSpans = N.getAll('.true__title .nav__title__name span span') 25 | let navTitleFlavourSpans = N.getAll('.true__title .nav__title__flavour span span') 26 | 27 | let navnB = N.get('.buffer__title .nav__title__name') 28 | let navfB = N.get('.buffer__title .nav__title__flavour') 29 | navnB.innerHTML = this.info.name 30 | navfB.innerHTML = this.info.flavour 31 | 32 | navnB.style.color = this.info.c 33 | navfB.style.color = this.info.c 34 | 35 | let navTitleFlavourBufferSpans = N.getAll('span span', navfB) 36 | let navTitleNameBufferSpans = N.getAll('span span', navnB) 37 | 38 | let backTooltip = N.get('.back__tooltip') 39 | backTooltip.style.color = this.info.c 40 | 41 | 42 | let page = N.get('.current__page'), 43 | pageSpan = N.getAll('span span', page) 44 | let pageBuffer = N.get('.buffer__page') 45 | pageBuffer.innerHTML = this.info.index 46 | pageBuffer.style.color = this.info.c 47 | 48 | let pageBufferSpans = N.getAll('span span', pageBuffer) 49 | let totalPage = N.get('.total__page'), 50 | totalPageSpan = N.getAll('span span', totalPage), 51 | totalPageBuffer = N.get('.total__page__buffer'), 52 | totalPageBufferSpans = N.getAll('span span', totalPageBuffer), 53 | total__page__wrapper = N.get('.total__page__wrapper') 54 | total__page__wrapper.style.color = this.info.c 55 | totalPageBuffer.style.color = this.info.c 56 | 57 | this.tl = new N.TL 58 | this.tl.from({ 59 | d: 1000, 60 | el: bB, 61 | p: { 62 | o: [0, 1] 63 | }, 64 | e: 'io5', 65 | }) 66 | 67 | this.tl.from({ 68 | d: 450, 69 | el: [...navTitleFlavourSpans, ...navTitleNameSpans, ...pageSpan, ...totalPageSpan], 70 | p: { 71 | x: [0, -101] 72 | }, 73 | cb: _ => { 74 | N.O(pageBuffer, 1) 75 | N.O(totalPageBuffer, 1) 76 | }, 77 | e: 'o5' 78 | }) 79 | 80 | this.tl.from({ 81 | d: 450, 82 | el: [...navTitleFlavourBufferSpans, ...navTitleNameBufferSpans, ...pageBufferSpans, ...totalPageBufferSpans 83 | ], 84 | p: { 85 | x: [-101, 0], 86 | }, 87 | cb: () => { 88 | this.calculNextState(navf, navn, navfB, navnB, page, pageBuffer, totalPage, totalPageBuffer) 89 | }, 90 | e: 'o5', 91 | delay: 450 92 | }) 93 | 94 | N.PE.none(this.button) 95 | this.canvasAnimation() 96 | 97 | } 98 | 99 | calculNextState(navf, navn, navfB, navnB, p, bp, total__page, total__page__buffer) { 100 | total__page.innerHTML = total__page__buffer.innerHTML 101 | total__page.style.color = this.info.c 102 | N.O(total__page__buffer, 0) 103 | 104 | p.innerHTML = bp.innerHTML 105 | p.style.color = this.info.c 106 | 107 | N.O(bp, 0) 108 | N.PE.all(this.wrapper) 109 | this.wrapper.style.color = this.info.c 110 | this.wrapper.style.backgroundColor = this.info.bg 111 | 112 | navf.innerHTML = navfB.innerHTML 113 | navn.innerHTML = navnB.innerHTML 114 | 115 | navf.style.color = this.info.c 116 | navn.style.color = this.info.c 117 | N.O(this.titleWrapperBuffer, 0) 118 | } 119 | 120 | play() { 121 | const fixations = N.getAll('.fixation') 122 | fixations.forEach(f => { 123 | f.style.backgroundColor = this.info.c 124 | }) 125 | 126 | const ressorts = N.getAll('ressort-button') 127 | ressorts.forEach(r => { 128 | r.style.color = this.info.c 129 | N.get('button', r).style.backgroundColor = this.info.c 130 | }) 131 | N.O(this.titleWrapperBuffer, 1) 132 | this.tl.play() 133 | } 134 | 135 | canvasAnimation() { 136 | } 137 | 138 | 139 | } 140 | 141 | -------------------------------------------------------------------------------- /src/animation/collectionsAnimationService.js: -------------------------------------------------------------------------------- 1 | import { TEXTURE } from "../Canvas/Preloader/preloaderCanvas" 2 | 3 | class CollectionsService { 4 | constructor() { 5 | this.currentPage = 2 6 | 7 | this.collectionsInfo = [ 8 | { 9 | bg: '#171717', c: '#E5DFDF', image1: 'collections/noise1.png', image2: 'collections/noise2.png', 10 | flavour: 'IA', 11 | name: 'Midjourney', 12 | index: '01', 13 | detailHTML: ` 14 |
midjourney-1
15 |
midjourney-2
16 |
midjourney-3
17 |
midjourney-4
`, 18 | 'dF': 'IA', 19 | 'dN': 'Midjourney' 20 | }, 21 | { 22 | bg: '#F0BDBD', c: '#FF4A0B', image1: 'collections/travis1.png', image2: 'collections/travis2.png', 23 | flavour: 'Typography', 24 | name: '