├── .github
└── workflows
│ └── build.yml
├── .gitignore
├── CNAME
├── LICENSE.md
├── build.sh
├── index.html
├── package-lock.json
├── package.json
├── pnpm-lock.yaml
├── public
├── buttons
│ ├── 88x31.png
│ ├── PoweredByNEXTSTEP.gif
│ ├── VisitNeXT.gif
│ ├── agplv3-with-text-162x68.webp
│ ├── any-browser.webp
│ ├── arc.gif
│ ├── arch.gif
│ ├── button.gif
│ ├── ce88x31.webp
│ ├── circular-88x31.gif
│ ├── dlbadge.webp
│ ├── dreamland-new.webp
│ ├── eightyeightthirtyone.webp
│ ├── firefox.gif
│ ├── foxmossbutton.webp
│ ├── freemusicnow.webp
│ ├── hg88x31.webp
│ ├── lucida-2.gif
│ ├── mariokart.webp
│ ├── melankorin.gif
│ ├── necoarc-88x31.webp
│ ├── omada.gif
│ ├── simpleanalytics.svg
│ ├── thinlqd.webp
│ └── wearr.gif
├── coolthings
│ ├── AppleInternal
│ │ ├── AB-Arcade.png
│ │ ├── AB-DemoEnd.png
│ │ ├── AB-Icon.png
│ │ ├── AB-Menu.png
│ │ ├── HDI.jpeg
│ │ ├── Pricing-appleconnect.png
│ │ ├── Pricing-icon.png
│ │ ├── Pricing-loginalert.png
│ │ ├── Pricing-services.png
│ │ ├── angrybirds.html
│ │ ├── hditestagent.html
│ │ ├── index.html
│ │ └── pricing.html
│ └── index.html
├── epic.ogg
├── favicon.ico
├── fonts
│ ├── body
│ │ ├── AdwaitaSans-Italic.ttf
│ │ ├── AdwaitaSans-Italic.woff
│ │ ├── AdwaitaSans-Italic.woff2
│ │ ├── AdwaitaSans-Regular.ttf
│ │ ├── AdwaitaSans-Regular.woff
│ │ └── AdwaitaSans-Regular.woff2
│ ├── display
│ │ ├── InterTight-Italic-VariableFont_wght.ttf
│ │ ├── InterTight-Italic-VariableFont_wght.woff
│ │ ├── InterTight-Italic-VariableFont_wght.woff2
│ │ ├── InterTight-VariableFont_wght.ttf
│ │ ├── InterTight-VariableFont_wght.woff
│ │ └── InterTight-VariableFont_wght.woff2
│ ├── mono
│ │ ├── AdwaitaMono-Bold.ttf
│ │ ├── AdwaitaMono-Bold.woff
│ │ ├── AdwaitaMono-Bold.woff2
│ │ ├── AdwaitaMono-BoldItalic.ttf
│ │ ├── AdwaitaMono-BoldItalic.woff
│ │ ├── AdwaitaMono-BoldItalic.woff2
│ │ ├── AdwaitaMono-Italic.ttf
│ │ ├── AdwaitaMono-Italic.woff
│ │ ├── AdwaitaMono-Italic.woff2
│ │ ├── AdwaitaMono-Regular.ttf
│ │ ├── AdwaitaMono-Regular.woff
│ │ └── AdwaitaMono-Regular.woff2
│ └── serif
│ │ ├── AppleGaramond Bd.ttf
│ │ ├── AppleGaramond BdIt.ttf
│ │ ├── AppleGaramond Bk.ttf
│ │ ├── AppleGaramond BkIt.ttf
│ │ ├── AppleGaramond Lt.ttf
│ │ └── AppleGaramond LtIt.ttf
├── index.css
├── kawaii.webp
├── legacy.css
├── legacy.html
├── main.css
├── modern-normalize.css
├── oneko-ctp.gif
├── oneko.gif
├── oneko.js
├── proj-thumbnails
│ ├── SSC2024_Social_Static_16x9.jpg
│ ├── Twitter Banner.png
│ ├── anura.webp
│ ├── appcommander.webp
│ ├── celeste.webp
│ ├── cowabunga.webp
│ ├── dssos.webp
│ ├── mandelapro.webp
│ ├── picasso.webp
│ └── placeholder.jpg
├── projects
│ └── index.html
├── style.css
├── styles.css
├── tools
│ ├── index.html
│ ├── jailbreakme
│ │ ├── _
│ │ │ └── iPhone1,x_3.1.3.pdf
│ │ ├── detector.js
│ │ ├── index.html
│ │ ├── slider.css
│ │ ├── slider.js
│ │ ├── star.css
│ │ ├── star.js
│ │ ├── sunspider-3dcube.js
│ │ ├── test.html
│ │ ├── ui_normal.css
│ │ └── wallpaper-retina.jpg
│ └── mememaker
│ │ ├── index.html
│ │ ├── script.js
│ │ └── style.css
└── typography.css
├── src
├── 3DSite
│ ├── 3DFloor.tsx
│ ├── ClickWall.tsx
│ ├── Screen.tsx
│ ├── ThreeDeeApp.tsx
│ └── ThreeDeeInfo.tsx
├── App.tsx
├── CommonCSS.tsx
├── Cursor.tsx
├── DarkReaderWarning.tsx
├── Footer.tsx
├── IsMobile.ts
├── LargeProjectView.tsx
├── LatestToot.tsx
├── N64.tsx
├── Navigation.tsx
├── Project.ts
├── ProjectCard.tsx
├── Projects.ts
├── SiteContent.tsx
├── Status.ts
├── Themes.tsx
├── Utils.ts
└── vite-env.d.ts
├── tsconfig.json
└── vite.config.ts
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | name: Build and Deploy (dreamland.js)
2 |
3 | on:
4 | # Runs on pushes targeting the default branch
5 | push:
6 | branches:
7 | - master
8 |
9 | # Allows you to run this workflow manually from the Actions tab
10 | workflow_dispatch:
11 |
12 | # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
13 | permissions:
14 | contents: read
15 | pages: write
16 | id-token: write
17 |
18 | # Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
19 | # However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
20 | concurrency:
21 | group: "pages"
22 | cancel-in-progress: false
23 |
24 | jobs:
25 | # Single deploy job since we're just deploying
26 | deploy:
27 | environment:
28 | name: github-pages
29 | url: ${{ steps.deployment.outputs.page_url }}
30 | runs-on: ubuntu-24.04
31 | steps:
32 | - name: Install pnpm
33 | uses: pnpm/action-setup@v4
34 | with:
35 | version: 10
36 | - name: Checkout
37 | uses: actions/checkout@v4
38 | - name: Setup Pages
39 | uses: actions/configure-pages@v5
40 | - name: Install Dependencies
41 | run: 'pnpm i'
42 | - name: 'Build'
43 | run: 'pnpm build'
44 | - name: 'Fix router'
45 | run: 'cp dist/index.html dist/404.html'
46 | - name: Upload artifact
47 | uses: actions/upload-pages-artifact@v3
48 | with:
49 | path: 'dist'
50 | - name: Deploy to GitHub Pages
51 | id: deployment
52 | uses: actions/deploy-pages@v4
53 |
--------------------------------------------------------------------------------
/.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 | .vite
27 |
--------------------------------------------------------------------------------
/CNAME:
--------------------------------------------------------------------------------
1 | bomberfish.ca
--------------------------------------------------------------------------------
/build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | npm run build
4 |
5 | for f in $(ls -d dist/assets/*.js); do
6 | echo "Appending licence info to $f"
7 | echo -e "// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-3.0\n$(cat $f)" > $f
8 | sed -i "\$i\\// @license-end" $f
9 | done
10 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | BomberFish
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
22 |
23 |
Hi 👋
24 |
25 | I'm Hariz, a high school student from Canada. I'm a
26 | wannabe "software engineer" and I sometimes do cool
27 | things.
28 |
29 |
30 | I'm interested in webdev, native iOS development, and a
31 | bit of security research.
32 |
33 |
34 |
35 |
About me
36 |
37 |
38 | I was one of the winners of the 2024 Swift Student
39 | Challenge
40 |
41 |
42 | I know the following programming languages (well):
43 |
44 | Swift (the GOAT)
45 | JavaScript/TypeScript
46 | C/C++/Objective-C
47 | Bash
48 | Python
49 |
50 |
51 |
52 | I'm a member of{" "}
53 |
54 | Mercury Workshop
55 |
56 |
57 | I play the guitar (!!)
58 | I use Arch (btw)
59 |
60 |
contacts
61 |
100 |
101 |
102 |
103 |
104 |
105 |
BomberFish
106 |
If you are are simple-minded, old, or irradiated in such a way that the future should not start with you, please direct yourself to the classic site.
107 |
Why am I here?
108 |
You probably fall in one of these categories:
109 |
110 | You are using an old browser. 2009 called, they want their IE8 back.
111 | You are scared of technology, and have disabled JavaScript. Shame on you.
112 | Something went very wrong, and the page failed to render. Check the browser console.
113 |
114 |
How do I get out?
115 |
Fix any problems listed above. It's really that simple.
116 |
117 |
118 |
131 |
132 |
133 |
134 |
135 |
142 |
152 |
153 |
157 |
158 |
159 |
160 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "bomberfish-website",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "tsc && vite build",
9 | "preview": "vite preview"
10 | },
11 | "devDependencies": {
12 | "terser": "^5.39.0",
13 | "typescript": "^5.8.3",
14 | "vite": "^6.3.4",
15 | "vite-plugin-minify": "^1.5.2"
16 | },
17 | "dependencies": {
18 | "@vitejs/plugin-legacy": "^6.1.1",
19 | "dreamland": "^0.0.24",
20 | "lightningcss": "^1.29.3",
21 | "vite-plugin-dreamland": "^1.2.1"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/public/buttons/88x31.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/buttons/88x31.png
--------------------------------------------------------------------------------
/public/buttons/PoweredByNEXTSTEP.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/buttons/PoweredByNEXTSTEP.gif
--------------------------------------------------------------------------------
/public/buttons/VisitNeXT.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/buttons/VisitNeXT.gif
--------------------------------------------------------------------------------
/public/buttons/agplv3-with-text-162x68.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/buttons/agplv3-with-text-162x68.webp
--------------------------------------------------------------------------------
/public/buttons/any-browser.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/buttons/any-browser.webp
--------------------------------------------------------------------------------
/public/buttons/arc.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/buttons/arc.gif
--------------------------------------------------------------------------------
/public/buttons/arch.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/buttons/arch.gif
--------------------------------------------------------------------------------
/public/buttons/button.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/buttons/button.gif
--------------------------------------------------------------------------------
/public/buttons/ce88x31.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/buttons/ce88x31.webp
--------------------------------------------------------------------------------
/public/buttons/circular-88x31.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/buttons/circular-88x31.gif
--------------------------------------------------------------------------------
/public/buttons/dlbadge.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/buttons/dlbadge.webp
--------------------------------------------------------------------------------
/public/buttons/dreamland-new.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/buttons/dreamland-new.webp
--------------------------------------------------------------------------------
/public/buttons/eightyeightthirtyone.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/buttons/eightyeightthirtyone.webp
--------------------------------------------------------------------------------
/public/buttons/firefox.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/buttons/firefox.gif
--------------------------------------------------------------------------------
/public/buttons/foxmossbutton.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/buttons/foxmossbutton.webp
--------------------------------------------------------------------------------
/public/buttons/freemusicnow.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/buttons/freemusicnow.webp
--------------------------------------------------------------------------------
/public/buttons/hg88x31.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/buttons/hg88x31.webp
--------------------------------------------------------------------------------
/public/buttons/lucida-2.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/buttons/lucida-2.gif
--------------------------------------------------------------------------------
/public/buttons/mariokart.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/buttons/mariokart.webp
--------------------------------------------------------------------------------
/public/buttons/melankorin.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/buttons/melankorin.gif
--------------------------------------------------------------------------------
/public/buttons/necoarc-88x31.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/buttons/necoarc-88x31.webp
--------------------------------------------------------------------------------
/public/buttons/omada.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/buttons/omada.gif
--------------------------------------------------------------------------------
/public/buttons/thinlqd.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/buttons/thinlqd.webp
--------------------------------------------------------------------------------
/public/buttons/wearr.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/buttons/wearr.gif
--------------------------------------------------------------------------------
/public/coolthings/AppleInternal/AB-Arcade.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/coolthings/AppleInternal/AB-Arcade.png
--------------------------------------------------------------------------------
/public/coolthings/AppleInternal/AB-DemoEnd.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/coolthings/AppleInternal/AB-DemoEnd.png
--------------------------------------------------------------------------------
/public/coolthings/AppleInternal/AB-Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/coolthings/AppleInternal/AB-Icon.png
--------------------------------------------------------------------------------
/public/coolthings/AppleInternal/AB-Menu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/coolthings/AppleInternal/AB-Menu.png
--------------------------------------------------------------------------------
/public/coolthings/AppleInternal/HDI.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/coolthings/AppleInternal/HDI.jpeg
--------------------------------------------------------------------------------
/public/coolthings/AppleInternal/Pricing-appleconnect.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/coolthings/AppleInternal/Pricing-appleconnect.png
--------------------------------------------------------------------------------
/public/coolthings/AppleInternal/Pricing-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/coolthings/AppleInternal/Pricing-icon.png
--------------------------------------------------------------------------------
/public/coolthings/AppleInternal/Pricing-loginalert.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/coolthings/AppleInternal/Pricing-loginalert.png
--------------------------------------------------------------------------------
/public/coolthings/AppleInternal/Pricing-services.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/coolthings/AppleInternal/Pricing-services.png
--------------------------------------------------------------------------------
/public/coolthings/AppleInternal/angrybirds.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | Angry Birds Reloaded - bomberfish.ca
11 |
12 |
13 | Angry Birds Reloaded Retail Demo (macOS)
14 | ❮ Go Back
15 | 🏛️ Download
16 | Bundle ID: com.rovio.abreloaded.retaildemo
17 | Latest known version: 1.0.13805 (13805)
18 | Latest leaked version: 1.0.13805 (13805)
19 | Signed by: Rovio Entertainment Oyj (D3S84ERWQK)
20 | Non-standard/private entitlements: None
21 | Created on: October 25, 2022 00:56:14
22 | Notes: Demo ends after ~15 levels
23 |
24 | AngryBirdsReloaded.app Icon
25 |
26 | Apple Arcade splash screen
27 |
28 | Main Menu (notice the demo text)
29 |
30 | Thanks for playing screen
31 |
32 |
33 |
--------------------------------------------------------------------------------
/public/coolthings/AppleInternal/hditestagent.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | Pricing - bomberfish.ca
11 |
12 |
13 | HDITestAgent
14 | ❮ Go Back
15 | Download unavailable
16 | Bundle ID: Unknown
17 | Latest known version: Unknown
18 | Latest leaked version: Unknown
19 | Signed by: Unknown
20 | Non-standard/private entitlements: Unknown
21 | Created on: Unknown
22 | Notes: Unknown if any version has been leaked. Perhaps check the 45GB dump on the IA?
23 |
24 | Images
25 | HDITestAgent's icon on an Apple Store employee's MacBook
26 |
27 |
28 |
--------------------------------------------------------------------------------
/public/coolthings/AppleInternal/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | Apple Internal - bomberfish.ca
11 |
12 |
13 | Apple Internal Software
14 | ❮ Go Back
15 | Pricing.app (macOS)
16 | Angry Birds Reloaded Retail Demo (macOS)
17 | HDITestAgent
18 |
19 |
--------------------------------------------------------------------------------
/public/coolthings/AppleInternal/pricing.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | Pricing - bomberfish.ca
11 |
12 |
13 | Pricing.app (macOS)
14 | ❮ Go Back
15 | 🏛️ Download
16 | Bundle ID: com.apple.ist.windward-mac
17 | Latest known version: 2.1.4 (275)
18 | Latest leaked version: 2.1.4 (275)
19 | Signed by: Apple Inc. - Retail IS&T Mac (8GHZHQX4WV)
20 | Non-standard/private entitlements: com.apple.private.mobilestoredemo.enabledemo
21 | Created on: October 25, 2022 00:14:25
22 | Notes: Requires AppleConnect Account
23 |
24 | Images
25 | Pricing.app Icon
26 |
27 | Welcome screen
28 |
29 | AppleConnect login
30 |
31 | "You need to sign in to use the app" prompt
32 |
33 |
34 |
--------------------------------------------------------------------------------
/public/coolthings/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | coolthings - bomberfish.ca
11 |
12 |
13 | Cool Things I found
14 | ❮ Go Back
15 | Apple Internal software
16 |
17 |
--------------------------------------------------------------------------------
/public/epic.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/epic.ogg
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/favicon.ico
--------------------------------------------------------------------------------
/public/fonts/body/AdwaitaSans-Italic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/fonts/body/AdwaitaSans-Italic.ttf
--------------------------------------------------------------------------------
/public/fonts/body/AdwaitaSans-Italic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/fonts/body/AdwaitaSans-Italic.woff
--------------------------------------------------------------------------------
/public/fonts/body/AdwaitaSans-Italic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/fonts/body/AdwaitaSans-Italic.woff2
--------------------------------------------------------------------------------
/public/fonts/body/AdwaitaSans-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/fonts/body/AdwaitaSans-Regular.ttf
--------------------------------------------------------------------------------
/public/fonts/body/AdwaitaSans-Regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/fonts/body/AdwaitaSans-Regular.woff
--------------------------------------------------------------------------------
/public/fonts/body/AdwaitaSans-Regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/fonts/body/AdwaitaSans-Regular.woff2
--------------------------------------------------------------------------------
/public/fonts/display/InterTight-Italic-VariableFont_wght.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/fonts/display/InterTight-Italic-VariableFont_wght.ttf
--------------------------------------------------------------------------------
/public/fonts/display/InterTight-Italic-VariableFont_wght.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/fonts/display/InterTight-Italic-VariableFont_wght.woff
--------------------------------------------------------------------------------
/public/fonts/display/InterTight-Italic-VariableFont_wght.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/fonts/display/InterTight-Italic-VariableFont_wght.woff2
--------------------------------------------------------------------------------
/public/fonts/display/InterTight-VariableFont_wght.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/fonts/display/InterTight-VariableFont_wght.ttf
--------------------------------------------------------------------------------
/public/fonts/display/InterTight-VariableFont_wght.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/fonts/display/InterTight-VariableFont_wght.woff
--------------------------------------------------------------------------------
/public/fonts/display/InterTight-VariableFont_wght.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/fonts/display/InterTight-VariableFont_wght.woff2
--------------------------------------------------------------------------------
/public/fonts/mono/AdwaitaMono-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/fonts/mono/AdwaitaMono-Bold.ttf
--------------------------------------------------------------------------------
/public/fonts/mono/AdwaitaMono-Bold.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/fonts/mono/AdwaitaMono-Bold.woff
--------------------------------------------------------------------------------
/public/fonts/mono/AdwaitaMono-Bold.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/fonts/mono/AdwaitaMono-Bold.woff2
--------------------------------------------------------------------------------
/public/fonts/mono/AdwaitaMono-BoldItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/fonts/mono/AdwaitaMono-BoldItalic.ttf
--------------------------------------------------------------------------------
/public/fonts/mono/AdwaitaMono-BoldItalic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/fonts/mono/AdwaitaMono-BoldItalic.woff
--------------------------------------------------------------------------------
/public/fonts/mono/AdwaitaMono-BoldItalic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/fonts/mono/AdwaitaMono-BoldItalic.woff2
--------------------------------------------------------------------------------
/public/fonts/mono/AdwaitaMono-Italic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/fonts/mono/AdwaitaMono-Italic.ttf
--------------------------------------------------------------------------------
/public/fonts/mono/AdwaitaMono-Italic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/fonts/mono/AdwaitaMono-Italic.woff
--------------------------------------------------------------------------------
/public/fonts/mono/AdwaitaMono-Italic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/fonts/mono/AdwaitaMono-Italic.woff2
--------------------------------------------------------------------------------
/public/fonts/mono/AdwaitaMono-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/fonts/mono/AdwaitaMono-Regular.ttf
--------------------------------------------------------------------------------
/public/fonts/mono/AdwaitaMono-Regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/fonts/mono/AdwaitaMono-Regular.woff
--------------------------------------------------------------------------------
/public/fonts/mono/AdwaitaMono-Regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/fonts/mono/AdwaitaMono-Regular.woff2
--------------------------------------------------------------------------------
/public/fonts/serif/AppleGaramond Bd.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/fonts/serif/AppleGaramond Bd.ttf
--------------------------------------------------------------------------------
/public/fonts/serif/AppleGaramond BdIt.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/fonts/serif/AppleGaramond BdIt.ttf
--------------------------------------------------------------------------------
/public/fonts/serif/AppleGaramond Bk.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/fonts/serif/AppleGaramond Bk.ttf
--------------------------------------------------------------------------------
/public/fonts/serif/AppleGaramond BkIt.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/fonts/serif/AppleGaramond BkIt.ttf
--------------------------------------------------------------------------------
/public/fonts/serif/AppleGaramond Lt.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/fonts/serif/AppleGaramond Lt.ttf
--------------------------------------------------------------------------------
/public/fonts/serif/AppleGaramond LtIt.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/fonts/serif/AppleGaramond LtIt.ttf
--------------------------------------------------------------------------------
/public/index.css:
--------------------------------------------------------------------------------
1 | legacy.css
--------------------------------------------------------------------------------
/public/kawaii.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/kawaii.webp
--------------------------------------------------------------------------------
/public/legacy.css:
--------------------------------------------------------------------------------
1 | /*
2 | * Prefixed by https://autoprefixer.github.io
3 | * PostCSS: v8.4.14,
4 | * Autoprefixer: v10.4.7
5 | * Browsers: last 999 version
6 | */
7 |
8 | @import url('/typography.css');
9 |
10 | body {
11 | background: #000000;
12 | color: #fbf9fb;
13 | font-family: var(--font-body), sans-serif;
14 | }
15 |
16 | h1,
17 | h2,
18 | h3,
19 | h4 {
20 | font-family: var(--font-serif), serif;
21 | }
22 |
23 | nav {
24 | background: #110f11;
25 | position: fixed;
26 | top: 0;
27 | left: 0;
28 | right: 0;
29 | z-index: 100;
30 | padding: 1em 0;
31 | width: 100vw;
32 | height: 2.5rem;
33 | margin: 0;
34 | padding: 5px;
35 | display: -webkit-box;
36 | display: -webkit-flex;
37 | display: -moz-box;
38 | display: -ms-flexbox;
39 | display: flex;
40 | -webkit-box-orient: horizontal;
41 | -webkit-box-direction: normal;
42 | -webkit-flex-direction: row;
43 | -moz-box-orient: horizontal;
44 | -moz-box-direction: normal;
45 | -ms-flex-direction: row;
46 | flex-direction: row;
47 | -webkit-box-align: center;
48 | -webkit-align-items: center;
49 | -moz-box-align: center;
50 | -ms-flex-align: center;
51 | align-items: center;
52 | }
53 |
54 | nav h2 {
55 | justify-self: flex-start;
56 | }
57 |
58 | nav span {
59 | justify-self: flex-end;
60 | margin-left: auto;
61 | padding-right: 1em;
62 | }
63 |
64 | main {
65 | margin-top: 2rem;
66 | padding: 1em;
67 | }
68 |
69 | img.circle {
70 | -webkit-border-radius: 100%;
71 | -moz-border-radius: 100%;
72 | border-radius: 100%;
73 | display: inline;
74 | margin-left: 1em;
75 | margin-right: 0.5em;
76 | -webkit-transition: -webkit-transform 0.5s cubic-bezier(0.3, 0, 0.6, 1);
77 | transition: -webkit-transform 0.5s cubic-bezier(0.3, 0, 0.6, 1);
78 | -o-transition: -o-transform 0.5s cubic-bezier(0.3, 0, 0.6, 1);
79 | -moz-transition: transform 0.5s cubic-bezier(0.3, 0, 0.6, 1),
80 | -moz-transform 0.5s cubic-bezier(0.3, 0, 0.6, 1);
81 | transition: transform 0.5s cubic-bezier(0.3, 0, 0.6, 1);
82 | transition: transform 0.5s cubic-bezier(0.3, 0, 0.6, 1),
83 | -webkit-transform 0.5s cubic-bezier(0.3, 0, 0.6, 1),
84 | -moz-transform 0.5s cubic-bezier(0.3, 0, 0.6, 1),
85 | -o-transform 0.5s cubic-bezier(0.3, 0, 0.6, 1);
86 | -webkit-transform: rotate(0deg);
87 | -moz-transform: rotate(0deg);
88 | -ms-transform: rotate(0deg);
89 | -o-transform: rotate(0deg);
90 | transform: rotate(0deg);
91 | background: black;
92 | padding: 3px;
93 | }
94 |
95 | a,
96 | a:visited:hover {
97 | color: #eba6ff;
98 | }
99 |
100 | a:visited {
101 | color: #cba6f7;
102 | }
103 |
104 | @media (prefers-color-scheme: light) {
105 | body {
106 | background: #eff1f5;
107 | color: #4c4f69;
108 | }
109 |
110 | a,
111 | a:visited:hover {
112 | color: #8839ef;
113 | }
114 |
115 | a:visited {
116 | color: #a16be6;
117 | }
118 |
119 | nav {
120 | background: #e6e9ef;
121 | }
122 | }
123 |
124 | h0 {
125 | font-size: 3em;
126 | font-weight: 700;
127 | margin: 0.67em 0;
128 | display: block;
129 | }
130 |
131 | * {
132 | outline-color: #eba6ff;
133 | }
134 |
--------------------------------------------------------------------------------
/public/legacy.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | BomberFish
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
20 | BomberFish
21 |
22 | Back to normal site |
23 | Blog
24 |
25 |
26 |
27 | About me
28 |
29 | I'm a 15 year old (aspiring) software developer from Canada, who
30 | loves tinkering with whatever devices I find.
31 |
32 | Things on this site
33 |
38 | Contact
39 |
40 |
41 | GitHub
42 |
43 |
44 | Twitter
45 |
46 |
47 | email (I don't
48 | check my emails often)
49 |
50 |
51 | Discord: @bomberfish, @hanz_was_here, @pageprotectionlayer, @securepagetablemonitor
52 |
53 |
54 | Signal: @bomberfish.77
55 |
56 |
57 |
58 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/public/main.css:
--------------------------------------------------------------------------------
1 | *:not(ul>li>ul, ul>li>ul>li, img, article section *) {
2 | transition: background-color .3s linear, color .1s linear, box-shadow .3s linear;
3 | }
4 |
5 | * {
6 | scrollbar-width: thin;
7 | scrollbar-color: var(--surface0) var(--crust);
8 | }
9 |
10 | ::selection {
11 | background: var(--accent);
12 | color: var(--base);
13 | }
14 |
15 | img::selection {
16 | background: color-mix(in srgb, var(--accent), transparent 40%);
17 | border: 1px solid var(--accent);
18 | }
19 |
20 | ::-webkit-scrollbar,
21 | *::-webkit-scrollbar {
22 | width: 6px;
23 | height: 6px;
24 | }
25 |
26 | ::-webkit-scrollbar-track,
27 | *::-webkit-scrollbar-track {
28 | background: var(--crust) !important;
29 | }
30 |
31 | ::-webkit-scrollbar-track-piece,
32 | *::-webkit-scrollbar-track-piece {
33 | background: var(--crust) !important;
34 | }
35 |
36 | ::-webkit-scrollbar-thumb,
37 | *::-webkit-scrollbar-thumb {
38 | background: var(--surface0) !important;
39 | border-radius: 9999px !important;
40 | margin: 0 2px !important;
41 | transition: background 0.2s !important;
42 | }
43 |
44 | ::-webkit-scrollbar-thumb:hover,
45 | *::-webkit-scrollbar-thumb:hover {
46 | background: var(--surface2) !important;
47 | transition: background 0.2s !important;
48 | }
49 |
50 | ::-webkit-scrollbar-button,
51 | *::-webkit-scrollbar-button,
52 | ::-webkit-scrollbar-corner,
53 | *::-webkit-scrollbar-corner {
54 | display: none !important;
55 | background: transparent !important;
56 | }
57 |
58 | :root {
59 | --crust: #000000;
60 | --base: #0f0e0f;
61 | --mantle: #050405;
62 | --text: #fffaff;
63 | --accent: #eba6ff;
64 | --overlay1: #8a888a;
65 | --surface2: #3d3a3d;
66 | --surface0: #1b181b;
67 | --subtext0: #a6a4a6;
68 | }
69 |
70 | :root {
71 | --perspective: 1000px;
72 | --gridsize: 50px;
73 | --bgmoveX: -19px;
74 | --bgmoveY: -19px;
75 | --bgscale: 1;
76 | }
77 |
78 | li::marker {
79 | color: var(--accent);
80 | }
81 |
82 | .no-js t {
83 | font-weight: 500;
84 | font-size: 1.2rem;
85 | }
86 |
87 | html,
88 | body {
89 | font-family: var(--font-body);
90 | font-size: 100%;
91 | margin: 0;
92 | padding: 0;
93 | }
94 |
95 | body {
96 | display: flex;
97 | justify-content: center;
98 | flex-direction: column;
99 | background: #0f0e0f;
100 | color: #fffaff;
101 | background: var(--crust);
102 | color: var(--text);
103 | overflow-x: hidden;
104 | }
105 |
106 | /* * {
107 | cursor: none!important;
108 | } */
109 |
110 | body {
111 | color-scheme: dark;
112 | }
113 |
114 | body.Latte {
115 | color-scheme: light;
116 | }
117 |
118 | html:has(body.cool),
119 | body.cool {
120 | display: initial;
121 | padding: 0;
122 | overflow: hidden;
123 | width: 100%;
124 | height: 100%;
125 | background: transparent;
126 | }
127 |
128 | body,
129 | body.cool {
130 | background: var(--mantle);
131 | background-image: radial-gradient(var(--surface0) calc(var(--bgscale) * var(--bgscale) * 1.5px),
132 | transparent 0);
133 | background-size: calc(20px * var(--bgscale)) calc(20px * var(--bgscale));
134 | background-position: var(--bgmoveX) var(--bgmoveY);
135 | }
136 |
137 | /*
138 | body:not(.cool) {
139 | transition: 0.4s background-position ease
140 | } */
141 |
142 | #oneko {
143 | z-index: 99999;
144 | }
145 |
146 | .secretEffect {
147 | border: 1px solid var(--overlay1);
148 | border-radius: 2rem;
149 | transition: transform 3s cubic-bezier(0.3, 0, 0.6, 1);
150 | transform-style: preserve-3d;
151 | perspective: 1000px;
152 | transform: rotate3d(1, 1, 1, 360deg);
153 | animation: scale 3s 1;
154 | transform-origin: 50vw 50vh;
155 | }
156 |
157 | @keyframes scale {
158 | 0% {
159 | scale: 1;
160 | }
161 |
162 | 50% {
163 | scale: 0.5;
164 | }
165 |
166 | 100% {
167 | scale: 1;
168 | }
169 | }
170 |
171 | @media (orientation: portrait) {
172 |
173 | main {
174 | display: initial !important;
175 | width: 100vw;
176 | }
177 |
178 | body {
179 | background: var(--base)
180 | }
181 |
182 | #darkreader-warning {
183 | width: 100vw;
184 | border-radius: 0;
185 | }
186 | }
187 |
188 |
189 |
190 | body.Latte .card:hover,
191 | body.Latte .card:focus,
192 | body.Latte .card:focus-visible {
193 | box-shadow: 0 0 20px rgba(24, 24, 37, 0.3);
194 | }
195 |
196 | body {
197 | line-height: 1.5;
198 | }
199 |
200 | #oneko {
201 | opacity: 0;
202 | background-position: -115.5px -115.5px;
203 | transition: 0.5s opacity;
204 | }
205 |
--------------------------------------------------------------------------------
/public/modern-normalize.css:
--------------------------------------------------------------------------------
1 | /*! modern-normalize v2.0.0 | MIT License | https://github.com/sindresorhus/modern-normalize */
2 | *,::after,::before{box-sizing:border-box}html{font-family:system-ui, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji';line-height:1.15;-webkit-text-size-adjust:100%;-moz-tab-size:4;tab-size:4}body{margin:0}hr{height:0;color:inherit}abbr[title]{text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace, SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-0.25em}sup{top:-0.5em}table{text-indent:0;border-color:inherit}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,select{text-transform:none}[type='button'],[type='reset'],[type='submit'],button{-webkit-appearance:button}::-moz-focus-inner{border-style:none;padding:0}:-moz-focusring{outline:1px dotted ButtonText}:-moz-ui-invalid{box-shadow:none}legend{padding:0}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type='search']{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}
--------------------------------------------------------------------------------
/public/oneko-ctp.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/oneko-ctp.gif
--------------------------------------------------------------------------------
/public/oneko.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/oneko.gif
--------------------------------------------------------------------------------
/public/oneko.js:
--------------------------------------------------------------------------------
1 | // oneko.js: https://github.com/adryd325/oneko.js
2 | // @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt Expat
3 |
4 | var _eventHandlers = {}; // somewhere global
5 |
6 | const addListener = (node, event, handler, capture = false) => {
7 | if (!(event in _eventHandlers)) {
8 | _eventHandlers[event] = [];
9 | }
10 | // here we track the events and their nodes (note that we cannot
11 | // use node as Object keys, as they'd get coerced into a string
12 | _eventHandlers[event].push({
13 | node: node,
14 | handler: handler,
15 | capture: capture,
16 | });
17 | node.addEventListener(event, handler, capture);
18 | };
19 |
20 | const removeAllListeners = (targetNode, event) => {
21 | // check if _eventHandlers[event] is defined
22 | if (_eventHandlers[event]) {
23 | // remove listeners from the matching nodes
24 | _eventHandlers[event]
25 | .filter(({ node }) => node === targetNode)
26 | .forEach(({ node, handler, capture }) =>
27 | node.removeEventListener(event, handler, capture)
28 | );
29 |
30 | // update _eventHandlers global
31 | _eventHandlers[event] = _eventHandlers[event].filter(
32 | ({ node }) => node !== targetNode
33 | );
34 | }
35 | };
36 |
37 | const mobileRE =
38 | /(android|bb\d+|meego).+mobile|armv7l|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series[46]0|samsungbrowser.*mobile|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i;
39 | const notMobileRE = /CrOS/;
40 |
41 | const tabletRE = /android|ipad|playbook|silk/i;
42 |
43 | function isMobile(opts) {
44 | if (!opts) opts = {};
45 | let ua = opts.ua;
46 | if (!ua && typeof navigator !== "undefined") ua = navigator.userAgent;
47 | if (ua && ua.headers && typeof ua.headers["user-agent"] === "string") {
48 | ua = ua.headers["user-agent"];
49 | }
50 | if (typeof ua !== "string") return false;
51 |
52 | let result =
53 | (mobileRE.test(ua) && !notMobileRE.test(ua)) ||
54 | (!!opts.tablet && tabletRE.test(ua));
55 |
56 | if (
57 | !result &&
58 | opts.tablet &&
59 | opts.featureDetect &&
60 | navigator &&
61 | navigator.maxTouchPoints > 1 &&
62 | ua.indexOf("Macintosh") !== -1 &&
63 | ua.indexOf("Safari") !== -1
64 | ) {
65 | result = true;
66 | }
67 |
68 | return result;
69 | }
70 |
71 | (function oneko() {
72 | if (isMobile({ tablet: true })) {
73 | return;
74 | }
75 | console.log("ONEKO INIT");
76 | const nekoRem = 2.75;
77 | const isReducedMotion =
78 | window.matchMedia(`(prefers-reduced-motion: reduce)`) === true ||
79 | window.matchMedia(`(prefers-reduced-motion: reduce)`).matches === true;
80 |
81 | if (isReducedMotion) return;
82 |
83 | const nekoEl = document.createElement("div");
84 |
85 | function convertRemToPixels(rem) {
86 | return (
87 | rem * parseFloat(getComputedStyle(document.documentElement).fontSize)
88 | );
89 | }
90 |
91 | let i = convertRemToPixels(3.5);
92 | let j = convertRemToPixels(2);
93 |
94 | let nekoPosX = i + j;
95 | let nekoPosY = i + 32;
96 |
97 | let mousePosX = i + j;
98 | let mousePosY = i + 32;
99 |
100 | let frameCount = 0;
101 | let idleTime = 0;
102 | let idleAnimation = null;
103 | let idleAnimationFrame = 0;
104 |
105 | const nekoSpeed = (16 * nekoRem) / 3;
106 | const spriteSets = {
107 | idle: [[-3, -3]],
108 | alert: [[-7, -3]],
109 | scratchSelf: [
110 | [-5, 0],
111 | [-6, 0],
112 | [-7, 0],
113 | ],
114 | scratchWallN: [
115 | [0, 0],
116 | [0, -1],
117 | ],
118 | scratchWallS: [
119 | [-7, -1],
120 | [-6, -2],
121 | ],
122 | scratchWallE: [
123 | [-2, -2],
124 | [-2, -3],
125 | ],
126 | scratchWallW: [
127 | [-4, 0],
128 | [-4, -1],
129 | ],
130 | tired: [[-3, -2]],
131 | sleeping: [
132 | [-2, 0],
133 | [-2, -1],
134 | ],
135 | N: [
136 | [-1, -2],
137 | [-1, -3],
138 | ],
139 | NE: [
140 | [0, -2],
141 | [0, -3],
142 | ],
143 | E: [
144 | [-3, 0],
145 | [-3, -1],
146 | ],
147 | SE: [
148 | [-5, -1],
149 | [-5, -2],
150 | ],
151 | S: [
152 | [-6, -3],
153 | [-7, -2],
154 | ],
155 | SW: [
156 | [-5, -3],
157 | [-6, -1],
158 | ],
159 | W: [
160 | [-4, -2],
161 | [-4, -3],
162 | ],
163 | NW: [
164 | [-1, 0],
165 | [-1, -1],
166 | ],
167 | };
168 |
169 | function init() {
170 | nekoEl.style.transition = "0.5s opacity";
171 | nekoEl.id = "oneko";
172 | nekoEl.ariaHidden = true;
173 | nekoEl.style.width = `${nekoRem}rem`;
174 | nekoEl.style.height = `${nekoRem}rem`;
175 | nekoEl.style.backgroundSize = `${convertRemToPixels(nekoRem) * 8}px ${
176 | convertRemToPixels(nekoRem) * 4
177 | }px`;
178 | nekoEl.style.position = "fixed";
179 | nekoEl.style.pointerEvents = "none";
180 | nekoEl.style.imageRendering = "pixelated";
181 | nekoEl.style.left = `${nekoPosX - 16}px`;
182 | nekoEl.style.top = `${nekoPosY - 16}px`;
183 | nekoEl.style.zIndex = Number.MAX_VALUE;
184 | setTimeout(() => {
185 | nekoEl.style.opacity = 1;
186 | }, 2);
187 |
188 | let nekoFile = "./oneko-ctp.gif";
189 | const curScript = document.currentScript;
190 | if (curScript && curScript.dataset.cat) {
191 | nekoFile = curScript.dataset.cat;
192 | }
193 | nekoEl.style.backgroundImage = `url(${nekoFile})`;
194 |
195 | document.body.appendChild(nekoEl);
196 |
197 | document.addEventListener("mousemove", function (event) {
198 | if (!document.getElementById("oneko")) {
199 | init();
200 | }
201 | mousePosX = event.clientX;
202 | mousePosY = event.clientY;
203 | });
204 |
205 | window.requestAnimationFrame(onAnimationFrame);
206 | }
207 |
208 | let lastFrameTimestamp;
209 |
210 | function onAnimationFrame(timestamp) {
211 | // Stops execution if the neko element is removed from DOM
212 | if (!nekoEl.isConnected) {
213 | return;
214 | }
215 | if (!lastFrameTimestamp) {
216 | lastFrameTimestamp = timestamp;
217 | }
218 | if (timestamp - lastFrameTimestamp > 100) {
219 | lastFrameTimestamp = timestamp;
220 | frame();
221 | }
222 | window.requestAnimationFrame(onAnimationFrame);
223 | }
224 |
225 | function setSprite(name, frame) {
226 | const sprite = spriteSets[name][frame % spriteSets[name].length];
227 | nekoEl.style.backgroundPosition = `${
228 | sprite[0] * convertRemToPixels(nekoRem)
229 | }px ${sprite[1] * convertRemToPixels(nekoRem)}px`;
230 | }
231 |
232 | function resetIdleAnimation() {
233 | idleAnimation = null;
234 | idleAnimationFrame = 0;
235 | }
236 |
237 | function idle() {
238 | idleTime += 1;
239 |
240 | // every ~ 12 seconds
241 | if (
242 | idleTime > 6 &&
243 | Math.floor(Math.random() * 200) == 0 &&
244 | idleAnimation == null
245 | ) {
246 | let avalibleIdleAnimations = ["sleeping", "scratchSelf"];
247 | if (nekoPosX < 16 * nekoRem - 20) {
248 | avalibleIdleAnimations.push("scratchWallW");
249 | }
250 | if (nekoPosY < 16 * nekoRem - 20) {
251 | avalibleIdleAnimations.push("scratchWallN");
252 | }
253 | if (nekoPosX > window.innerWidth - (16 * nekoRem - 20)) {
254 | avalibleIdleAnimations.push("scratchWallE");
255 | }
256 | if (nekoPosY > window.innerHeight - (16 * nekoRem - 20)) {
257 | avalibleIdleAnimations.push("scratchWallS");
258 | }
259 | console.log(avalibleIdleAnimations);
260 | idleAnimation =
261 | avalibleIdleAnimations[
262 | Math.floor(Math.random() * avalibleIdleAnimations.length)
263 | ];
264 | }
265 |
266 | switch (idleAnimation) {
267 | case "sleeping":
268 | if (idleAnimationFrame < 8) {
269 | setSprite("tired", 0);
270 | break;
271 | }
272 | setSprite("sleeping", Math.floor(idleAnimationFrame / 4));
273 | removeAllListeners(nekoEl, "click");
274 | addListener(nekoEl, "click", () => {
275 | resetIdleAnimation();
276 | });
277 | if (idleAnimationFrame > 192) {
278 | resetIdleAnimation();
279 | }
280 | break;
281 | case "scratchWallN":
282 | case "scratchWallS":
283 | case "scratchWallE":
284 | case "scratchWallW":
285 | case "scratchSelf":
286 | setSprite(idleAnimation, idleAnimationFrame);
287 | if (idleAnimationFrame > 9) {
288 | resetIdleAnimation();
289 | }
290 | break;
291 | default:
292 | setSprite("idle", 0);
293 | return;
294 | }
295 | idleAnimationFrame += 1;
296 | }
297 |
298 | function frame() {
299 | frameCount += 1;
300 | const diffX = nekoPosX - mousePosX;
301 | const diffY = nekoPosY - mousePosY;
302 | const distance = Math.sqrt(diffX ** 2 + diffY ** 2);
303 |
304 | if (distance < nekoSpeed || distance < 48) {
305 | idle();
306 | return;
307 | }
308 |
309 | idleAnimation = null;
310 | idleAnimationFrame = 0;
311 |
312 | if (idleTime > 1) {
313 | setSprite("alert", 0);
314 | // count down after being alerted before moving
315 | idleTime = Math.min(idleTime, 3.5);
316 | idleTime -= 1;
317 | return;
318 | }
319 |
320 | let direction;
321 | direction = diffY / distance > 0.5 ? "N" : "";
322 | direction += diffY / distance < -0.5 ? "S" : "";
323 | direction += diffX / distance > 0.5 ? "W" : "";
324 | direction += diffX / distance < -0.5 ? "E" : "";
325 | setSprite(direction, frameCount);
326 |
327 | nekoPosX -= (diffX / distance) * nekoSpeed;
328 | nekoPosY -= (diffY / distance) * nekoSpeed;
329 |
330 | nekoPosX = Math.min(Math.max(16, nekoPosX), window.innerWidth - 16);
331 | nekoPosY = Math.min(Math.max(16, nekoPosY), window.innerHeight - 16);
332 |
333 | nekoEl.style.left = `${nekoPosX - 16}px`;
334 | nekoEl.style.top = `${nekoPosY - 16}px`;
335 | }
336 |
337 | init();
338 | })();
339 |
340 | // @license-end
341 |
--------------------------------------------------------------------------------
/public/proj-thumbnails/SSC2024_Social_Static_16x9.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/proj-thumbnails/SSC2024_Social_Static_16x9.jpg
--------------------------------------------------------------------------------
/public/proj-thumbnails/Twitter Banner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/proj-thumbnails/Twitter Banner.png
--------------------------------------------------------------------------------
/public/proj-thumbnails/anura.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/proj-thumbnails/anura.webp
--------------------------------------------------------------------------------
/public/proj-thumbnails/appcommander.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/proj-thumbnails/appcommander.webp
--------------------------------------------------------------------------------
/public/proj-thumbnails/celeste.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/proj-thumbnails/celeste.webp
--------------------------------------------------------------------------------
/public/proj-thumbnails/cowabunga.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/proj-thumbnails/cowabunga.webp
--------------------------------------------------------------------------------
/public/proj-thumbnails/dssos.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/proj-thumbnails/dssos.webp
--------------------------------------------------------------------------------
/public/proj-thumbnails/mandelapro.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/proj-thumbnails/mandelapro.webp
--------------------------------------------------------------------------------
/public/proj-thumbnails/picasso.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/proj-thumbnails/picasso.webp
--------------------------------------------------------------------------------
/public/proj-thumbnails/placeholder.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/proj-thumbnails/placeholder.jpg
--------------------------------------------------------------------------------
/public/projects/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | Home - bomberfish.ca
11 |
12 |
13 | My Projects
14 | ❮ Go Back
15 | MacDirtyCow Apps
16 | Whitelist – Un-blacklist all enterprise-signed apps
17 | COMING SOON: AppCommander – A swiss army knife for your iPhone apps.
18 | ControlConfig – Customize your Control Center. Collab with sneakyf1shy .
19 | Freeload – Remove the 3-app limit on free Developer Accounts.
20 | Mandela Rewritten
21 | Mandela - Customization app
22 | Cowabunga (Various Contributions)
23 | Other iOS apps
24 | InstaSpring - Instantly respring your device.
25 | COMING SOON: Harmonize - Tune your instrument
26 | Other Projects
27 | This website (on GitHub)
28 | Orphan Destroyer: Weird Discord Bot
29 | Simple fraction reducer in python. Made for a math assessment.
30 | 3D Test in Godot. Uses gyro on mobile I think.
31 |
32 |
--------------------------------------------------------------------------------
/public/style.css:
--------------------------------------------------------------------------------
1 | legacy.css
--------------------------------------------------------------------------------
/public/styles.css:
--------------------------------------------------------------------------------
1 | legacy.css
--------------------------------------------------------------------------------
/public/tools/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
17 |
18 | Games - bomberfish.ca
19 |
20 |
21 | Tools
22 | <- Back
23 | Random Number Generator
25 | Simple Meme Generator
26 | JailbreakMe 2.0 (3.1.2-4.0.1)
28 | TrollGuide - TrollStore Easy Install
30 | IPA Installer test
31 | Signed IPAs for popular jailbreak apps
34 | SnapchatTweakInstaller - Install Snapchat++ on iPhone
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/public/tools/jailbreakme/_/iPhone1,x_3.1.3.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/tools/jailbreakme/_/iPhone1,x_3.1.3.pdf
--------------------------------------------------------------------------------
/public/tools/jailbreakme/detector.js:
--------------------------------------------------------------------------------
1 | var agent = navigator.userAgent;
2 | var index = agent.indexOf("OS ");
3 | firmware = agent.slice(index + "OS ".length);
4 | firmware = firmware.slice(0, firmware.indexOf(" "));
5 | firmware = firmware.replace(/_/g, ".");
6 | var ssi = getSunSpiderInterval();
7 | window.location = '#' + ssi;
8 | window.page = './_/iPhone1,x_3.1.3.pdf'
9 | _ = new Image(window.page);
--------------------------------------------------------------------------------
/public/tools/jailbreakme/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | JailbreakMe
9 |
10 |
11 |
12 |
13 |
JailbreakMe
14 | by comex (et al.)
15 |
16 |
17 |
18 |
19 |
20 |
JailbreakMe 2.0
21 |
Jailbreak to get tweaks and apps Apple won't allow in the App Store. Free, legal, safe.
22 |
You should sync with iTunes before using this tool.
23 |
24 |
25 |
❮ Back
26 |
More Info ❯
27 |
28 |
29 |
39 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/public/tools/jailbreakme/slider.css:
--------------------------------------------------------------------------------
1 | #unlock1, #unlock2 {
2 | -webkit-border-radius: 13px;
3 | }
4 |
5 | #unlock1 {
6 | border: 1px solid rgba(30, 30, 30, 0.88);
7 | margin-top: 22px;
8 | width: 282px;
9 | margin-left: auto;
10 | margin-right:auto;
11 | }
12 |
13 | #unlock2 {
14 | width: 282px;
15 | height: 50px;
16 | border: 1px solid rgba(100, 100, 100, 0.88);
17 | background-color: rgba(0, 0, 0, 0.77);
18 | position: relative;
19 | }
20 |
21 | #unlock_text {
22 | position: absolute;
23 |
24 | text-align: center;
25 | left: 90px;
26 | top: 12px;
27 |
28 | color: #ffffff;
29 |
30 | font-size: 22px;
31 | font-family: Helvetica;
32 |
33 | -webkit-animation-name: slide;
34 | -webkit-animation-duration: 0.5s;
35 | -webkit-animation-iteration-count: infinite;
36 | -webkit-mask-image: -webkit-gradient(linear, left bottom, right bottom, from(rgba(0,0,0,0.5)), to(rgba(0,0,0,0.5)));
37 | }
38 |
39 | #arrow {
40 | margin-top: 2px;
41 | margin-left: 0px;
42 | position: absolute;
43 | }
44 |
--------------------------------------------------------------------------------
/public/tools/jailbreakme/slider.js:
--------------------------------------------------------------------------------
1 | /* slider */
2 | var step;
3 | var unlock4 = document.getElementById('unlock_text');
4 | var unlock1 = document.getElementById('unlock1');
5 | var ival = null;
6 |
7 | // returns a -webkit-gradient string for an infinite gradient
8 | // there is probably a simpler way to do this.
9 | function get_gradient(bits) {
10 | var last = -10000;
11 | var last_alpha = -10000;
12 | var ret = '-webkit-gradient(linear, left bottom, right bottom, ';
13 | var stops = '';
14 | var on = false;
15 | //console.log('bits='+bits);
16 | for(var i = 0; i < bits.length; i += 2) {
17 | var pos = bits[i];
18 | var alpha = bits[i+1];
19 | if(!on && pos >= 0) {
20 | var from = (alpha * (0 - last_pos) - last_alpha * (0 - pos)) / (pos - last_pos);
21 | ret += 'from(rgba(0,0,0,' + from + ')), ';
22 | on = true;
23 | }
24 | if(on) {
25 | if(pos >= 1) {
26 | // last_alpha + ((alpha - last_alpha) / (pos - last_pos)) * (1 - last_pos);
27 | // [1/[pos - last_pos]](last_alpha*pos - last_alpha*last_pos + alpha - alpha*last_pos - last_alpha + last_alpha*last_pos)
28 | // [1/[pos - last_pos]](last_alpha*(pos - 1) + alpha(1 - last_pos))
29 |
30 | var to = (alpha * (1 - last_pos) - last_alpha * (1 - pos)) / (pos - last_pos);
31 | ret += 'to(rgba(0,0,0,' + to + '))';
32 | ret += stops;
33 | break;
34 | }
35 | stops += ', color-stop(' + pos + ', rgba(0,0,0,' + alpha + '))';
36 | }
37 | last_pos = pos;
38 | last_alpha = alpha;
39 | }
40 | return ret + ')';
41 | }
42 | function turn_on() {
43 | if(ival) return;
44 | step = -0.15;
45 | ival = setInterval(window.stepp = function() {
46 | step = (step + 0.05) % 1.55;
47 | var wleft = step - 0.15;
48 | var wright = step;
49 | var gleft = wleft - 0.2;
50 | var gright = wright + 0.2;
51 | var s = get_gradient([-1000, 0.5, gleft, 0.5, wleft, 0.9, wright, 0.9, gright, 0.5, 1000, 0.5]);
52 | //console.log('step='+step+' s='+s);
53 | unlock4.style.WebkitMaskImage = s;
54 | }, 50);
55 | }
56 | function turn_off() {
57 | if(!ival) return;
58 | clearInterval(ival);
59 | ival = null;
60 | unlock4.style.WebkitMaskImage = '';
61 | }
62 |
63 | var left = 0;
64 | function set_left(left_) {
65 | left = left_;
66 | slider.style.left = left_ + 'px';
67 | unlock4.style.opacity = 1.0 - (left / 40);
68 | }
69 |
70 | var startX = null, startLeft, maxLeft;
71 |
72 | var vmismatch = 0;
73 |
74 | slider.ontouchstart = function(e) {
75 | startX = e.targetTouches[0].clientX;
76 | startLeft = left;
77 | turn_off();
78 | slider.style.WebkitTransitionProperty = '';
79 | slider.style.WebkitTransitionDuration = '0s';
80 | unlock4.style.WebkitTransitionProperty = '';
81 | unlock4.style.WebkitTransitionDuration = '0s';
82 | maxLeft = slider.parentNode.clientWidth - slider.clientWidth - 5;
83 | return false;
84 | }
85 | slider.ontouchmove = function(e) {
86 | var diff = e.targetTouches[0].clientX - startX;
87 | if(diff < 0) diff = 0;
88 | else if(diff >= maxLeft) diff = maxLeft;
89 | set_left(diff + startLeft);
90 | }
91 | window.ontouchend = function() {
92 | if(startX == null) return;
93 | startX = null;
94 | if(maxLeft - left < 15) {
95 | jailbreak();
96 | return false;
97 | }
98 | turn_on();
99 | unlock4.style.WebkitTransitionProperty = 'opacity';
100 | unlock4.style.WebkitTransitionDuration = '0.5s';
101 | var left_ = left;
102 | set_left(0);
103 | slider.style.WebkitTransform = 'translateX('+left_+'px)';
104 | setTimeout(function() {
105 | slider.style.WebkitTransitionProperty = '-webkit-transform';
106 | slider.style.WebkitTransitionDuration = '0.5s';
107 | slider.style.WebkitTransform = 'translateX(0px)';
108 | }, 0);
109 | return false;
110 | }
111 |
112 | set_left(0);
113 | turn_on();
114 |
--------------------------------------------------------------------------------
/public/tools/jailbreakme/star.css:
--------------------------------------------------------------------------------
1 |
2 | body {
3 | margin: 0;
4 | padding: 0;
5 |
6 | background: #000;
7 | background-repeat: no-repeat;
8 |
9 | font-family: "Helvetica", sans-serif;
10 | -webkit-user-select: none;
11 | }
12 |
13 | /* iphone portrait */
14 | @media screen and (min-width: 320px) and (max-width: 320px) {
15 | body {
16 | height: 416px;
17 | background-image: url('wallpaper-iphone.jpg');
18 | }
19 | }
20 |
21 | /* iphone landscape */
22 | @media screen and (min-width: 480px) and (max-width: 480px){
23 | body {
24 | height: 269px;
25 | background-image: url('wallpaper-iphone.jpg');
26 | }
27 | }
28 |
29 | /* ipad landscape */
30 | @media screen and (min-width: 1024px) and (max-width: 1024px) {
31 | body {
32 | height: 691px;
33 | background-image: url('wallpaper-ipad.jpg');
34 | }
35 | }
36 |
37 | /* ipad portrait */
38 | @media screen and (min-width: 768px) and (max-width: 768px) {
39 | body {
40 | height: 947px;
41 | background-image: url('wallpaper-ipad.jpg');
42 | }
43 | }
44 |
45 | /* retina! */
46 | @media screen and (-webkit-min-device-pixel-ratio: 2) {
47 | body {
48 | font-family: "Helvetica Neue", sans-serif;
49 | background-image: url('wallpaper-retina.jpg');
50 | background-size: 480px 480px;
51 | }
52 | }
53 |
54 | ::selection { background: transparent; }
55 | ::-moz-selection { background: transparent; }
56 |
--------------------------------------------------------------------------------
/public/tools/jailbreakme/star.js:
--------------------------------------------------------------------------------
1 | var onetext = 'Oops...
It looks like the installer crashed last time you tried to jailbreak. :(
It might work if you try again.
';
2 | var twotext = 'It worked!
Tap the Cydia icon to get started with your jailbreak.
(If you restored from a backup, you might be seeing this even though you\'re not jailbroken yet.)
';
3 | var toooldtext = 'JailbreakMe
Version too old. You need to upgrade using iTunes before you can use this site.
';
4 | var toonewtext = 'Welp.
Version too new. You need to downgrade to 4.0.1/3.2.1 or earlier (which may be impossible,
explanation ) before you can use this site.
';
5 |
6 | function add_animations(elem) {
7 | elem.style.webkitTransitionProperty = "-webkit-transform, opacity";
8 | elem.style.webkitTransitionDuration = '0.4s, 0.4s';
9 | }
10 |
11 | function get_progress() {
12 | var then = 0;
13 | var then_progress = 0;
14 | var matches = document.cookie.match(/progress=[0-9]_[0-9\.]+/g);
15 | if(matches) {
16 | for(var i = 0; i < matches.length; i++) {
17 | var m = matches[i];
18 | var t = parseInt(m.substring(11));
19 | if(t > then) {
20 | then = t;
21 | then_progress = parseInt(m.substring(9, 10));
22 | }
23 | }
24 | }
25 | return then_progress;
26 | }
27 |
28 | var my_progress = 0;
29 | window.onload = function() {
30 | //return; // XXX
31 | if(vmismatch == -1) {
32 | document.getElementById('texts').innerHTML = toooldtext;
33 | return;
34 | } else if(vmismatch == 1) {
35 | document.getElementById('texts').innerHTML = toonewtext;
36 | return;
37 | }
38 | var prog = get_progress();
39 | if(prog == 1) {
40 | document.getElementById('texts').innerHTML = onetext;
41 | } else if(prog == 2) {
42 | document.getElementById('texts').innerHTML = twotext;
43 | }
44 | }
45 |
46 | /*function show_x1() {
47 | document.getElementById('podtext').innerHTML = pt;
48 | document.documentElement.style.WebkitTransitionProperty = '-webkit-transform';
49 | document.documentElement.style.WebkitTransitionDuration = '0.2s';
50 | document.documentElement.style.WebkitTransitionTimingFunction = 'linear';
51 | document.documentElement.style.WebkitTransform = 'translateY(-60px)';
52 | var pod = document.getElementById('pod');
53 | pod.style.display = 'block';
54 | }
55 |
56 | show_x1();*/
57 |
58 |
59 | function jailbreak() {
60 | var middle = document.getElementsByClassName("middle_wrapper")[0];
61 | add_animations(middle);
62 | middle.style.opacity = '0';
63 |
64 | var toolbar = document.getElementsByClassName("tool_bar")[0];
65 | add_animations(toolbar);
66 | toolbar.style.opacity = '0';
67 | toolbar.style.webkitTransform = 'translateY(96px)';
68 |
69 | var topbar = document.getElementsByClassName("top_bar")[0];
70 | add_animations(topbar);
71 | topbar.style.opacity = '0';
72 | topbar.style.webkitTransform = 'translateY(-96px)';
73 |
74 | jailbreak_real();
75 | }
76 |
77 | //setTimeout(jailbreak, 300);
78 |
79 | function jailbreak_real() {
80 | document.cookie = 'progress=1_' + (new Date().getTime()/1000) + ';domain=wrxck.github.io/jailbreakme;path=/;expires=Sat, 01 Feb 2020 05:00:00 GMT';
81 |
82 | if(!window.page) {
83 | alert('There was no page... ' + navigator.userAgent);
84 | }
85 | //alert(page);// + " with the interval: " + _sunSpiderInterval);
86 |
87 | var i = document.createElement("iframe");
88 | i.setAttribute("src", page);
89 | i.style.position = 'absolute';
90 | i.style.opacity = '0.000001';
91 | i.style.width = '100px';
92 | i.style.height = '100px';
93 | i.style.zIndex = '-9999';
94 |
95 | document.body.appendChild(i);
96 |
97 | pival = setInterval(function() {
98 | var prog = get_progress();
99 | if(prog == 2) {
100 | clearInterval(pival);
101 | window.location = 'index.html';
102 | } else if(prog == 3) {
103 | clearInterval(pival);
104 | window.location = window.location;
105 | }
106 | }, 500);
107 | }
108 |
109 | var old = window.orientation;
110 | function ooc(e) {
111 | if (old != window.orientation)
112 | window.scrollTo(0, 1);
113 |
114 | old = window.orientation;
115 | }
116 |
117 | function loaded() {
118 | setTimeout(function() {
119 | window.scrollTo(0, 1);
120 | }, 10);
121 | }
122 |
123 | window.addEventListener('load', function (e) { loaded(); setInterval(ooc, 100) }, false);
124 | window.addEventListener('onorientationchange', ooc, false);
125 |
126 |
127 | document.addEventListener('touchmove', function(e) {
128 | e.preventDefault();
129 | }, false);
130 |
--------------------------------------------------------------------------------
/public/tools/jailbreakme/sunspider-3dcube.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (C) 2007 Apple Inc. All rights reserved.
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions
6 | are met:
7 | 1. Redistributions of source code must retain the above copyright
8 | notice, this list of conditions and the following disclaimer.
9 | 2. Redistributions in binary form must reproduce the above copyright
10 | notice, this list of conditions and the following disclaimer in the
11 | documentation and/or other materials provided with the distribution.
12 |
13 | THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 | PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 | OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 | */
25 | var _sunSpiderInterval = 0;
26 | function getSunSpiderInterval() {
27 | if(_sunSpiderInterval)return _sunSpiderInterval;
28 | var _sunSpiderStartDate=new Date,Q=[],MTrans=[],MQube=[],I=[],Origin={},Testing={},LoopTimer,DisplArea={};DisplArea.Width=300;DisplArea.Height=300;function DrawLine(a,c){var d=a.V[0],b=c.V[0],e=a.V[1],f=c.V[1],g=Math.abs(b-d),h=Math.abs(f-e),m=d,n=e,k,j,l;if(b>=d)b=d=1;else b=d=-1;if(f>=e)f=e=1;else f=e=-1;if(g>=h){f=d=0;k=g;j=g/2;l=h;g=g}else{e=b=0;k=h;j=h/2;l=g;g=h}g=Math.round(Q.LastPx+g);for(h=Q.LastPx;h=k){j-=k;m+=d;n+=e}m+=b;n+=f}Q.LastPx=g}
29 | function CalcCross(a,c){var d=[];d[0]=a[1]*c[2]-a[2]*c[1];d[1]=a[2]*c[0]-a[0]*c[2];d[2]=a[0]*c[1]-a[1]*c[0];return d}function CalcNormal(a,c,d){for(var b=[],e=[],f=0;f<3;f++){b[f]=a[f]-c[f];e[f]=d[f]-c[f]}b=CalcCross(b,e);a=Math.sqrt(b[0]*b[0]+b[1]*b[1]+b[2]*b[2]);for(f=0;f<3;f++)b[f]/=a;b[3]=1;return b}function CreateP(a,c,d){this.V=[a,c,d,1]}
30 | function MMulti(a,c){for(var d=[[],[],[],[]],b=0,e=0;b<4;b++)for(e=0;e<4;e++)d[b][e]=a[b][0]*c[0][e]+a[b][1]*c[1][e]+a[b][2]*c[2][e]+a[b][3]*c[3][e];return d}function VMulti(a,c){for(var d=[],b=0;b<4;b++)d[b]=a[b][0]*c[0]+a[b][1]*c[1]+a[b][2]*c[2]+a[b][3]*c[3];return d}function VMulti2(a,c){for(var d=[],b=0;b<3;b++)d[b]=a[b][0]*c[0]+a[b][1]*c[1]+a[b][2]*c[2];return d}function MAdd(a,c){for(var d=[[],[],[],[]],b=0,e=0;b<4;b++)for(e=0;e<4;e++)d[b][e]=a[b][e]+c[b][e];return d}
31 | function Translate(a,c,d,b){return MMulti([[1,0,0,c],[0,1,0,d],[0,0,1,b],[0,0,0,1]],a)}function RotateX(a,c){var d=c;d*=Math.PI/180;var b=Math.cos(d);d=Math.sin(d);return MMulti([[1,0,0,0],[0,b,-d,0],[0,d,b,0],[0,0,0,1]],a)}function RotateY(a,c){var d=c;d*=Math.PI/180;var b=Math.cos(d);d=Math.sin(d);return MMulti([[b,0,d,0],[0,1,0,0],[-d,0,b,0],[0,0,0,1]],a)}function RotateZ(a,c){var d=c;d*=Math.PI/180;var b=Math.cos(d);d=Math.sin(d);return MMulti([[b,-d,0,0],[d,b,0,0],[0,0,1,0],[0,0,0,1]],a)}
32 | function DrawQube(){var a=[],c=5;for(Q.LastPx=0;c>-1;c--)a[c]=VMulti2(MQube,Q.Normal[c]);if(a[0][2]<0){if(!Q.Line[0]){DrawLine(Q[0],Q[1]);Q.Line[0]=true}if(!Q.Line[1]){DrawLine(Q[1],Q[2]);Q.Line[1]=true}if(!Q.Line[2]){DrawLine(Q[2],Q[3]);Q.Line[2]=true}if(!Q.Line[3]){DrawLine(Q[3],Q[0]);Q.Line[3]=true}}if(a[1][2]<0){if(!Q.Line[2]){DrawLine(Q[3],Q[2]);Q.Line[2]=true}if(!Q.Line[9]){DrawLine(Q[2],Q[6]);Q.Line[9]=true}if(!Q.Line[6]){DrawLine(Q[6],Q[7]);Q.Line[6]=true}if(!Q.Line[10]){DrawLine(Q[7],Q[3]);
33 | Q.Line[10]=true}}if(a[2][2]<0){if(!Q.Line[4]){DrawLine(Q[4],Q[5]);Q.Line[4]=true}if(!Q.Line[5]){DrawLine(Q[5],Q[6]);Q.Line[5]=true}if(!Q.Line[6]){DrawLine(Q[6],Q[7]);Q.Line[6]=true}if(!Q.Line[7]){DrawLine(Q[7],Q[4]);Q.Line[7]=true}}if(a[3][2]<0){if(!Q.Line[4]){DrawLine(Q[4],Q[5]);Q.Line[4]=true}if(!Q.Line[8]){DrawLine(Q[5],Q[1]);Q.Line[8]=true}if(!Q.Line[0]){DrawLine(Q[1],Q[0]);Q.Line[0]=true}if(!Q.Line[11]){DrawLine(Q[0],Q[4]);Q.Line[11]=true}}if(a[4][2]<0){if(!Q.Line[11]){DrawLine(Q[4],Q[0]);Q.Line[11]=
34 | true}if(!Q.Line[3]){DrawLine(Q[0],Q[3]);Q.Line[3]=true}if(!Q.Line[10]){DrawLine(Q[3],Q[7]);Q.Line[10]=true}if(!Q.Line[7]){DrawLine(Q[7],Q[4]);Q.Line[7]=true}}if(a[5][2]<0){if(!Q.Line[8]){DrawLine(Q[1],Q[5]);Q.Line[8]=true}if(!Q.Line[5]){DrawLine(Q[5],Q[6]);Q.Line[5]=true}if(!Q.Line[9]){DrawLine(Q[6],Q[2]);Q.Line[9]=true}if(!Q.Line[1]){DrawLine(Q[2],Q[1]);Q.Line[1]=true}}Q.Line=[false,false,false,false,false,false,false,false,false,false,false,false];Q.LastPx=0}
35 | function Loop(){if(!(Testing.LoopCount>Testing.LoopMax)){for(var a=String(Testing.LoopCount);a.length<3;)a="0"+a;MTrans=Translate(I,-Q[8].V[0],-Q[8].V[1],-Q[8].V[2]);MTrans=RotateX(MTrans,1);MTrans=RotateY(MTrans,3);MTrans=RotateZ(MTrans,5);MTrans=Translate(MTrans,Q[8].V[0],Q[8].V[1],Q[8].V[2]);MQube=MMulti(MTrans,MQube);for(a=8;a>-1;a--)Q[a].V=VMulti(MTrans,Q[a].V);DrawQube();Testing.LoopCount++;Loop()}}
36 | function Init(a){Origin.V=[150,150,20,1];Testing.LoopCount=0;Testing.LoopMax=50;Testing.TimeMax=0;Testing.TimeAvg=0;Testing.TimeMin=0;Testing.TimeTemp=0;Testing.TimeTotal=0;Testing.Init=false;MTrans=[[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1]];MQube=[[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1]];I=[[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1]];Q[0]=new CreateP(-a,-a,a);Q[1]=new CreateP(-a,a,a);Q[2]=new CreateP(a,a,a);Q[3]=new CreateP(a,-a,a);Q[4]=new CreateP(-a,-a,-a);Q[5]=new CreateP(-a,a,-a);Q[6]=new CreateP(a,
37 | a,-a);Q[7]=new CreateP(a,-a,-a);Q[8]=new CreateP(0,0,0);Q.Edge=[[0,1,2],[3,2,6],[7,6,5],[4,5,1],[4,0,3],[1,5,6]];Q.Normal=[];for(var c=0;c
2 |
3 |
4 |
5 | JailbreakMe
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/public/tools/jailbreakme/ui_normal.css:
--------------------------------------------------------------------------------
1 | .top_bar {
2 | width: 100%;
3 | position: absolute;
4 | top: 0;
5 | height: 96px;
6 |
7 | text-align: center;
8 | background: -webkit-gradient(linear, left top, left bottom, from(#222222), to(#000), color-stop(0.5, rgba(21, 21, 21, 0.7)), color-stop(0.5, rgba(0, 0, 0, 0.7)));
9 | border-bottom: 1px solid #343434;
10 | }
11 |
12 | .top_bar h1 {
13 | margin-top: 5px;
14 | font-size: 52px;
15 |
16 | font-weight: lighter;
17 |
18 | color: #f0f0f0;
19 | text-shadow: #000 0px -2px 0px;
20 | }
21 |
22 | .top_bar h2 {
23 | opacity: 1;
24 | margin-top: -2.20em;
25 | font-weight: normal;
26 | color: #fff;
27 | font-size: 16px;
28 | text-shadow: #000 0px -2px 0px;
29 | }
30 |
31 | .middle_wrapper {
32 | position: absolute;
33 | top: 96px;
34 | width: 100%;
35 | }
36 |
37 | .bubble {
38 | margin-top: 27px;
39 | margin-right: auto;
40 | margin-left: auto;
41 |
42 | /*background-color: rgba(0, 20, 70, 0.796875);*/
43 | background-color: rgba(55, 55, 55, 0.815624);
44 | border: 3px solid rgba(190, 196, 208, 0.937500);
45 | border-radius: 11px;
46 |
47 | /* fix apple's stupid ipad bug */
48 | -webkit-border-top-left-radius: 11px;
49 | -webkit-border-top-right-radius: 11px;
50 | -webkit-border-bottom-left-radius: 11px;
51 | -webkit-border-bottom-right-radius: 11px;
52 |
53 | -webkit-box-shadow: 0px 4px 4px rgba(0, 0, 0, 0.4);
54 | text-shadow: #000 0px -1px 0px;
55 | width: 262px;
56 | height: 177px;
57 |
58 | font-size: 16px;
59 | text-align: center;
60 | color: white;
61 | position: relative;
62 |
63 | padding: 0 5px;
64 |
65 | }
66 |
67 | .slider {
68 | width: 59px;
69 | height: 44px;
70 | border-radius: 10px;
71 | -webkit-border-radius: 10px;
72 | -webkit-border-top-left-radius: 10px;
73 | -webkit-border-top-right-radius: 10px;
74 | -webkit-border-bottom-left-radius: 10px;
75 | -webkit-border-bottom-right-radius: 10px;
76 | margin-top: 2px;
77 | margin-left: 2px;
78 | border: 1px solid #ccc;
79 | -webkit-box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.4);
80 | background: -webkit-gradient(linear, left top, left bottom, from(#f8f8f8), to(#919191));
81 | position: relative;
82 | /*-webkit-transform: scale(10);*/
83 | }
84 | .arrow {
85 | position: absolute;
86 | left: 16px;
87 | top: 12px;
88 | }
89 | .shadow {
90 | -webkit-border-radius: 0px;
91 | -webkit-border-bottom-right-radius: 10px;
92 | -webkit-border-bottom-left-radius: 10px;
93 | -moz-border-radius-bottomright: 10px;
94 | -moz-border-radius-bottomleft: 10px;
95 | background-color: rgba(255, 255, 255, 0.4);
96 | position: absolute;
97 | left: 50%;
98 | margin-left: -10px;
99 | width: 20px;
100 | height: 25px;
101 | -webkit-transform: scaleX(13.6) /* 272/20 */
102 | }
103 | .ttext {
104 | margin-top: 5px;
105 | }
106 | .ttitle {
107 | font-weight: bold;
108 | margin-top: 7px;
109 | margin-bottom: 5px;
110 | }
111 |
112 | .tbottom {
113 | font-weight: bold;
114 | position: absolute;
115 | bottom: 14px;
116 | }
117 |
118 | .ttop {
119 | padding-top: 5px;
120 | }
121 |
122 | .bubble a {
123 | display: block;
124 | width: 100%;
125 |
126 | text-decoration: none;
127 | color: white;
128 | }
129 |
130 | .tool_bar {
131 | position: absolute;
132 | top: 325px;
133 | height: 96px;
134 | width: 100%;
135 |
136 | background: -webkit-gradient(linear, left top, left bottom, from(rgba(34, 34, 34, 0.7)), to(rgba(0, 0, 0, 0.7)), color-stop(0.5, rgba(21, 21, 21, 0.7)), color-stop(0.5, rgba(0, 0, 0, 0.7)));
137 | border-top: 1px solid #343434;
138 | }
139 |
140 | /*#pod {
141 | position: fixed;
142 | top: 416px;
143 | display: none;
144 | height: 60px;
145 | width: 100%;
146 | background: -webkit-gradient(linear, left top, left bottom, from(#777), to(#777), color-stop(0.5, #444));
147 | }
148 | #podtext {
149 | margin: 5px;
150 | color: #eee;
151 | text-shadow: #000 0px -1px 0px;
152 | } */
153 |
154 |
155 | /* landscape iphone */
156 | @media screen and (min-width: 480px) and (max-width: 480px) {
157 | .tool_bar {
158 | top: 195px;
159 | /*height: 20px;*/
160 | }
161 | #by {
162 | padding-left: 5px;
163 | }
164 | /*#pod {
165 | top: 269px;
166 | }*/
167 | #unlock1 {
168 | margin-top: 10px !important;
169 | }
170 | .top_bar {
171 | height: 20px;
172 | padding-top: 10px;
173 | padding-bottom: 10px;
174 | }
175 | .top_bar h1 {
176 | display: inline;
177 | font-size: 18px;
178 | }
179 | .top_bar h2 {
180 | display: inline;
181 | font-size: 12px;
182 | }
183 |
184 | .ttop {
185 | display: none;
186 | margin-bottom: -12px;
187 | }
188 | .middle {
189 | width: 430px;
190 | height: 140px;
191 | margin-top: -51px;
192 | }
193 | .tbutton {
194 | width: 212px;
195 | }
196 | .trightbutton {
197 | left: 222px;
198 | }
199 | .tbuttonhighlight {
200 | width: 203px;
201 | }
202 | .shadow {
203 | -webkit-transform: scaleX(22) /* 440/20 */
204 | }
205 | .ttext {
206 | padding-left: 20px;
207 | padding-right: 20px;
208 | margin-top: 15px;
209 | }
210 | }
211 |
212 | /* iPad portrait */
213 | @media screen and (min-width: 768px) and (max-width: 768px) {
214 | .tool_bar {
215 | top: 817px;
216 | }
217 | .middle {
218 | margin-top: 260px;
219 | }
220 | }
221 |
222 | /* iPad landscape */
223 | @media screen and (min-width: 1024px) and (max-width: 1024px) {
224 | .tool_bar {
225 | top: 595px;
226 | }
227 | .middle {
228 | margin-top: 140px;
229 | }
230 | }
231 |
--------------------------------------------------------------------------------
/public/tools/jailbreakme/wallpaper-retina.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BomberFish/BomberFish.github.io/8ee1040da7cd7452ecc4e6f91eca2e41f1ca67a9/public/tools/jailbreakme/wallpaper-retina.jpg
--------------------------------------------------------------------------------
/public/tools/mememaker/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Super Epic Meme Generator™ - bomberfish.ca
9 |
10 |
11 |
12 |
13 |
14 | ❮ Go Back
15 |
29 |
30 |
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/public/tools/mememaker/script.js:
--------------------------------------------------------------------------------
1 | // @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-3.0
2 | console.log("OwO what's this")
3 | function updateTop() {
4 | var topInput = document.getElementById("topInput");
5 | var topText = document.getElementById("topText");
6 | topText.innerHTML = topInput.value;
7 | }
8 |
9 | function updateBottom() {
10 | var bottomInput = document.getElementById("bottomInput");
11 | var bottomText = document.getElementById("bottomText");
12 | bottomText.innerHTML = bottomInput.value;
13 | }
14 |
15 | function updateImg() {
16 | var img = document.querySelector('img');
17 | var file = document.querySelector('input[type=file]').files[0];
18 | img.src = window.URL.createObjectURL(file);
19 | }
20 | // @license-end
--------------------------------------------------------------------------------
/public/tools/mememaker/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | background-color: white;
3 | color: black;
4 | font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI Variable', 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif
5 | }
6 |
7 | @media (prefers-color-scheme: dark) {
8 | body {
9 | background-color: black;
10 | color: white;
11 | }
12 | }
13 |
14 | .memeText {
15 | background-color: transparent;
16 | font-family: Impact, Haettenschweiler, "Franklin Gothic Bold", Charcoal, "Helvetica Inserat", "Bitstream Vera Sans Bold", "Arial Black", sans-serif;
17 | font-size: 40px;
18 | font-style: normal;
19 | font-variant: normal;
20 | text-align: center;
21 | font-weight: 700;
22 | line-height: 44px;
23 | color: white;
24 | text-shadow: rgba(0, 0, 0, 0.3) 0px 0px 10px;
25 | width: 600px;
26 | position: absolute;
27 | -webkit-text-stroke-width: 1px;
28 | -webkit-text-stroke-color: black;
29 | /* Futureproofing yay */
30 | text-stroke-width: 1px;
31 | text-stroke-color: black;
32 | }
33 |
34 | #topText {
35 | top: 2%;
36 | left: 50%;
37 | transform: translate(-50%, -2%);
38 | }
39 |
40 | #bottomText {
41 | top: 95%;
42 | left: 50%;
43 | transform: translate(-50%, -95%);
44 | }
45 |
46 | #wrapper {
47 | position: relative;
48 | text-align: center;
49 | color: white;
50 | }
--------------------------------------------------------------------------------
/public/typography.css:
--------------------------------------------------------------------------------
1 | @font-face {
2 | font-family: "Inter Tight";
3 | src: local("Inter Tight"),url("https://bomberfish.ca/fonts/display/InterTight-VariableFont_wght.woff2") format("woff2"),url("https://bomberfish.ca/fonts/display/InterTight-VariableFont_wght.woff") format("woff"),url("https://bomberfish.ca/fonts/display/InterTight-VariableFont_wght.ttf") format("truetype");
4 | font-weight: 100 900;
5 | font-style: normal;
6 | font-display: swap;
7 | }
8 | @font-face {
9 | font-family: "Inter Tight";
10 | src: local("Inter Tight"),url("https://bomberfish.ca/fonts/display/InterTight-Italic-VariableFont_wght.woff2") format("woff2"),url("https://bomberfish.ca/fonts/display/InterTight-Italic-VariableFont_wght.woff") format("woff"),url("https://bomberfish.ca/fonts/display/InterTight-Italic-VariableFont_wght.ttf") format("truetype");
11 | font-weight: 100 900;
12 | font-style: italic;
13 | font-display: swap;
14 | }
15 |
16 | @font-face {
17 | font-family: "Adwaita Sans";
18 | src: local("Adwaita Sans"),url("https://bomberfish.ca/fonts/body/AdwaitaSans-Regular.woff2") format("woff2"),url("https://bomberfish.ca/fonts/body/AdwaitaSans-Regular.woff") format("woff"),url("https://bomberfish.ca/fonts/body/AdwaitaSans-Regular.ttf") format("truetype");
19 | font-weight: 100 900;
20 | font-style: normal;
21 | font-display: swap;
22 | }
23 |
24 | @font-face {
25 | font-family: "Adwaita Sans";
26 | src: local("Adwaita Sans"),url("https://bomberfish.ca/fonts/body/AdwaitaSans-Italic.woff2") format("woff2"),url("https://bomberfish.ca/fonts/body/AdwaitaSans-Italic.woff") format("woff"),url("https://bomberfish.ca/fonts/body/AdwaitaSans-Italic.ttf") format("truetype");
27 | font-weight: 100 900;
28 | font-style: italic;
29 | font-display: swap;
30 | }
31 |
32 | @font-face {
33 | font-family: "Adwaita Mono";
34 | src: local("Adwaita Mono"),url("https://bomberfish.ca/fonts/mono/AdwaitaMono-Regular.woff2") format("woff2"),url("https://bomberfish.ca/fonts/mono/AdwaitaMono-Regular.woff") format("woff"),url("https://bomberfish.ca/fonts/mono/AdwaitaMono-Regular.ttf") format("truetype");
35 | font-weight: normal;
36 | font-style: normal;
37 | font-display: swap;
38 | }
39 |
40 | @font-face {
41 | font-family: "Adwaita Mono";
42 | src: local("Adwaita Mono"),url("https://bomberfish.ca/fonts/mono/AdwaitaMono-Italic.woff2") format("woff2"),url("https://bomberfish.ca/fonts/mono/AdwaitaMono-Italic.woff") format("woff"),url("https://bomberfish.ca/fonts/mono/AdwaitaMono-Italic.ttf") format("truetype");
43 | font-weight: normal;
44 | font-style: italic;
45 | font-display: swap;
46 | }
47 |
48 | @font-face {
49 | font-family: "Adwaita Mono";
50 | src: local("Adwaita Mono"),url("https://bomberfish.ca/fonts/mono/AdwaitaMono-Bold.woff2") format("woff2"),url("https://bomberfish.ca/fonts/mono/AdwaitaMono-Bold.woff") format("woff"),url("https://bomberfish.ca/fonts/mono/AdwaitaMono-Bold.ttf") format("truetype");
51 | font-weight: bold;
52 | font-style: normal;
53 | font-display: swap;
54 | }
55 |
56 | @font-face {
57 | font-family: "Adwaita Mono";
58 | src: local("Adwaita Mono"),url("https://bomberfish.ca/fonts/mono/AdwaitaMono-BoldItalic.woff2") format("woff2"),url("https://bomberfish.ca/fonts/mono/AdwaitaMono-BoldItalic.woff") format("woff"),url("https://bomberfish.ca/fonts/mono/AdwaitaMono-BoldItalic.ttf") format("truetype");
59 | font-weight: bold;
60 | font-style: italic;
61 | font-display: swap;
62 | }
63 |
64 | @font-face {
65 | font-family: "Material Symbols Rounded";
66 | font-style: normal;
67 | font-weight: 400;
68 | font-display: swap;
69 | src: url(https://fonts.gstatic.com/s/materialsymbolsrounded/v181/syl0-zNym6YjUruM-QrEh7-nyTnjDwKNJ_190FjpZIvDmUSVOK7BDB_Qb9vUSzq3wzLK-P0J-V_Zs-QtQth3-jOcbTCVpeRL2w5rwZu2rIelXxc.woff2)
70 | format("woff2");
71 | }
72 |
73 |
74 | @font-face {
75 | font-family: "Apple Garamond";
76 | src: url("/fonts/serif/AppleGaramond Bk.ttf") format("truetype"),local("Apple Garamond"),local("ITC Garamond Condensed"),local("ITC Garamond"),local("Garamond"),local("Adobe Garamond"),local("EB Garamond");
77 | font-weight: normal;
78 | font-style: normal;
79 | }
80 |
81 | @font-face {
82 | font-family: "Apple Garamond";
83 | src: url("/fonts/serif/AppleGaramond BkIt.ttf") format("truetype"),local("Apple Garamond"),local("ITC Garamond Condensed"),local("ITC Garamond"),local("Garamond"),local("Adobe Garamond"),local("EB Garamond");
84 | font-weight: normal;
85 | font-style: italic;
86 | }
87 |
88 | @font-face {
89 | font-family: "Apple Garamond";
90 | src: url("/fonts/serif/AppleGaramond Bd.ttf") format("truetype"),local("Apple Garamond"),local("ITC Garamond Condensed"),local("ITC Garamond"),local("Garamond"),local("Adobe Garamond"),local("EB Garamond");
91 | font-weight: bolder;
92 | font-style: normal;
93 | }
94 | @font-face {
95 | font-family: "Apple Garamond";
96 | src: url("/fonts/serif/AppleGaramond BdIt.ttf") format("truetype"),local("Apple Garamond"),local("ITC Garamond Condensed"),local("ITC Garamond"),local("Garamond"),local("Adobe Garamond"),local("EB Garamond");
97 | font-weight: bolder;
98 | font-style: italic;
99 | }
100 | @font-face {
101 | font-family: "Apple Garamond";
102 | src: url("/fonts/serif/AppleGaramond Lt.ttf") format("truetype"),local("Apple Garamond Light"),local("Apple Garamond"),local("ITC Garamond Condensed"),local("ITC Garamond"),local("Garamond"),local("Adobe Garamond"),local("EB Garamond");
103 | font-weight: lighter;
104 | font-style: normal;
105 | }
106 | @font-face {
107 | font-family: "Apple Garamond";
108 | src: url("/fonts/serif/AppleGaramond LtIt.ttf") format("truetype"),local("Apple Garamond Light"),local("Apple Garamond"),local("ITC Garamond Condensed"),local("ITC Garamond"),local("Garamond"),local("Adobe Garamond"),local("EB Garamond");
109 | font-weight: lighter;
110 | font-style: italic;
111 | }
112 | .material-symbols-rounded {
113 | font-family: "Material Symbols Rounded";
114 | font-weight: normal;
115 | font-style: normal;
116 | font-size: 24px;
117 | line-height: 1;
118 | letter-spacing: normal;
119 | text-transform: none;
120 | display: inline-block;
121 | white-space: nowrap;
122 | word-wrap: normal;
123 | direction: ltr;
124 | -webkit-font-feature-settings: "liga";
125 | -webkit-font-smoothing: antialiased;
126 | }
127 | :root {
128 | --font-display: "Inter Tight", "Adwaita Sans", Inter, "SF Pro Display", "SF Pro",
129 | "SF Pro Text", -apple-system, BlinkMacSystemFont, system-ui,
130 | "Helvetica Neue", Helvetica, Arial, sans-serif, "Apple Color Emoji",
131 | "Noto Color Emoji", "Segoe UI Emoji";
132 | --font-body: "Adwaita Sans", Inter, "SF Pro Text", "SF Pro", -apple-system,
133 | BlinkMacSystemFont, system-ui, "Helvetica Neue", Helvetica, Arial,
134 | sans-serif, "Apple Color Emoji", "Noto Color Emoji", "Segoe UI Emoji";
135 | --font-mono: "Adwaita Mono", "Iosveka", "Source Code Pro", ui-monospace, monospace;
136 | --font-serif: "Apple Garamond", "ITC Garamond Condensed", "ITC Garamond", "Garamond", "Adobe Garamond", "EB Garamond", "Times New Roman", Times, "Linux Libertine", serif;
137 | }
138 |
--------------------------------------------------------------------------------
/src/3DSite/3DFloor.tsx:
--------------------------------------------------------------------------------
1 | import "dreamland";
2 |
3 | export const SuperCoolAndEpicDanceFloor: Component<{}, {}> = function () {
4 | this.css = `
5 | display: grid;
6 | grid-template-rows: repeat(9, 1fr);
7 | grid-template-columns: repeat(7, 1fr);
8 |
9 | .tile {
10 | background: var(--base);
11 | border: 10px solid var(--mantle);
12 | animation: 1s linear infinite forwards borderPulse;
13 | width: 150px;
14 | height: 150px;
15 | }
16 |
17 | @keyframes borderPulse {
18 | 0% {
19 | border-color: var(--crust);
20 | }
21 | 10%, 20% {
22 | border-color: var(--accent);
23 | }
24 | 7% {
25 | border-color: color-mix(in srgb, white 20%, var(--accent))
26 | }
27 | 85%, 100% {
28 | border-color: var(--crust);
29 | }
30 | }
31 |
32 | `;
33 |
34 | return (
35 |
36 | {/* mother of all jank */}
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | );
110 | };
111 |
--------------------------------------------------------------------------------
/src/3DSite/ClickWall.tsx:
--------------------------------------------------------------------------------
1 | import "dreamland";
2 |
3 | export const ClickWall: Component<{}, {}> = function () {
4 | this.css = `
5 | position: absolute;
6 | top: 0;
7 | left: 0;
8 | bottom: 0;
9 | right: 0;
10 | backdrop-filter: blur(40px);
11 | -webkit-backdrop-filter: blur(40px);
12 | background: rgba(0, 0, 0, 0.8);
13 | z-index: 1000;
14 | display: grid;
15 | place-items: center;
16 | font-size: 3rem;
17 | transition: 0.4s;
18 |
19 |
20 | &.transparent {
21 | background: rgba(255, 255, 255, 0);
22 | backdrop-filter: blur(0px);
23 | -webkit-backdrop-filter: blur(0px);
24 | opacity: 0;
25 | transition: 0.4s;
26 | pointer-events: none;
27 | }
28 | `;
29 |
30 | return (
31 | {
33 | this.root.classList.add("transparent");
34 | setTimeout(() => {
35 | this.root.remove();
36 | }, 400);
37 | document.dispatchEvent(new Event("music-restart"));
38 | }}
39 | >
40 |
Click to continue
41 |
42 | );
43 | };
44 |
--------------------------------------------------------------------------------
/src/3DSite/Screen.tsx:
--------------------------------------------------------------------------------
1 | import "dreamland";
2 |
3 | export const Screen: Component<
4 | {
5 | x?: number;
6 | y?: number;
7 | z?: number;
8 | rx?: number;
9 | ry?: number;
10 | rz?: number;
11 | width?: number;
12 | height?: number;
13 | autoHeight?: boolean;
14 | nomove?: boolean;
15 | },
16 | {
17 | children: Element;
18 | }
19 | > = function () {
20 | this.css = `
21 | position: absolute;
22 | top: 0;
23 | left: 0;
24 | bottom: 0;
25 |
26 | width: ${this.width + "px" || "auto"};
27 | height: ${this.height + "px" || "auto"};
28 |
29 | transition: 0.75s transform ease-out;
30 |
31 | transform-origin: 50% 0;
32 | transform: rotateX(calc(var(--rX))) rotateY(calc(var(--rY))) rotateZ(calc(var(--rZ))) translate3d(calc(var(--pX)*var(--gridsize)),calc(var(--pY)*var(--gridsize)),calc(var(--pZ)*var(--gridsize)));
33 |
34 | article {
35 | background: color-mix(in srgb, var(--crust), transparent 20%);
36 | backdrop-filter: blur(10px);
37 | -webkit-backdrop-filter: blur(10px);
38 | padding: 0.75em;
39 | border-radius: 1rem;
40 | border: 1px solid var(--surface0);
41 | transition: 0.3s;
42 | overflow: auto;
43 | height: ${this.autoHeight ? "auto" : "100%"};
44 |
45 | resize: both;
46 |
47 | &:hover {
48 | border-color: var(--accent);
49 | transition: 0.3s;
50 | }
51 |
52 | width: 100%;
53 | }
54 | `;
55 |
56 | this.x ||= 0;
57 | this.y ||= 0;
58 | this.z ||= 0;
59 | this.rx ||= 0;
60 | this.ry ||= 0;
61 | this.rz ||= 0;
62 |
63 | this.mount = () => {
64 | // works around a bug i will fix later
65 | useChange(
66 | use`--pX: ${this.x || 0}; --pY: ${this.y || 0}; --pZ: ${this.z || 0
67 | }; --rX: ${this.rx || 0}deg; --rY: ${this.ry || 0}deg; --rZ: ${this.rz || 0
68 | }deg`,
69 | (v) => ((this.root as HTMLElement).style.cssText = v)
70 | );
71 | };
72 |
73 | return (
74 | {
76 | if (this.rz !== undefined && !this.nomove) {
77 | this.z! += 0.3;
78 | }
79 | }}
80 | on:mouseleave={() => {
81 | if (this.rz !== undefined && !this.nomove) {
82 | this.z! -= 0.3;
83 | }
84 | }}
85 | on:dblclick={() => {
86 | if (this.rz !== undefined && !this.nomove) {
87 | this.rz! += 360;
88 | }
89 | }}
90 | >
91 | {this.children}
92 |
93 | );
94 | };
95 |
--------------------------------------------------------------------------------
/src/3DSite/ThreeDeeApp.tsx:
--------------------------------------------------------------------------------
1 | import "dreamland";
2 | import ProjectCardDetails from "../Project";
3 | import { projects } from "../Projects";
4 | import { ProjectList } from "../ProjectCard";
5 | import { Screen } from "./Screen";
6 | import { sharedCSS } from "../CommonCSS";
7 | import { store } from "../App";
8 | import { ThreeDeeInfo } from "./ThreeDeeInfo";
9 | import { FullArticle } from "../SiteContent";
10 | import { convertRemToPixels } from "../Utils";
11 | import { SuperCoolAndEpicDanceFloor } from "./3DFloor";
12 | import { Footer } from "../Footer";
13 | import { LatestToot } from "../LatestToot";
14 |
15 | let keys = new Map();
16 | document.addEventListener("keydown", (e) => {
17 | keys.set(e.key, true);
18 | });
19 | document.addEventListener("keyup", (e) => {
20 | keys.delete(e.key);
21 | });
22 | function keydown(key: string) {
23 | return keys.has(key);
24 | }
25 |
26 | function numberInput(text: string, initialValue: number): number {
27 | let ans = prompt(text, initialValue.toString());
28 | if (ans) {
29 | if (isNaN(+ans)) {
30 | alert("Invalid input");
31 | return initialValue;
32 | }
33 | return +ans;
34 | }
35 | return initialValue;
36 | }
37 |
38 | export const ThreeDeeApp: Component<
39 | {},
40 | {
41 | projects: ProjectCardDetails[];
42 | rotation: number;
43 | x: number;
44 | y: number;
45 | z: number;
46 | r: number;
47 | speed: number;
48 | mult: number;
49 | }
50 | > = function () {
51 | this.projects = projects;
52 | this.rotation = 0;
53 | this.speed = 5;
54 | this.mult = 2;
55 |
56 | this.css = `
57 | width: 100%;
58 | height: 100%;
59 | perspective: var(--perspective);
60 |
61 | * {
62 | image-rendering: pixelated;
63 | -webkit-image-rendering: pixelated;
64 | }
65 |
66 | camera {
67 | position: absolute;
68 | inset: 0;
69 | pointer-events: all;
70 | perspective: var(--perspective);
71 | backface-visibility: hidden;
72 | contain: layout style size;
73 | width: 100%;
74 | height: 100%;
75 | transform-style: preserve-3d;
76 | will-change: transform;
77 | }
78 |
79 | stage {
80 | position: fixed;
81 | top: 50%!important;
82 | left: 50%!important;
83 | inset: 0;
84 | backface-visibility: shown;
85 | transform-style: preserve-3d;
86 | }
87 |
88 | debug {
89 | font-family: var(--font-display);
90 | font-size: 1.25rem;
91 | font-weight: 600;
92 | margin: 0;
93 | position: fixed;
94 | top: 0;
95 | left: 0;
96 | padding-top: 0.5rem;
97 | padding-left: 0.8rem;
98 | width: 10em;
99 |
100 | border-radius: 0 0 0.5em 0;
101 |
102 | z-index: 999;
103 |
104 | background: color-mix(in srgb, var(--base), transparent 30%);
105 |
106 | a {
107 | display: flex;
108 | text-decoration: none;
109 | font-size: 100%!important;
110 | }
111 | }
112 | input {
113 | accent-color: var(--accent);
114 | }
115 |
116 | }
117 | `;
118 |
119 | this.x = window.innerWidth / -40;
120 | this.y = window.innerHeight / 2;
121 | this.z = -200;
122 | this.r = -18;
123 |
124 | this.mount = () => {
125 | // alert(window.innerWidth)
126 | function easeOutCirc(x: number) {
127 | return Math.sqrt(1 - Math.pow(x - 1, 2));
128 | }
129 |
130 | console.debug("mount");
131 | const c = Math.abs(
132 | -(1000 + (2188 /* god this is so jank */ / window.innerWidth) * 200) -
133 | this.z,
134 | );
135 | console.debug(c);
136 | for (let i = 0; i < c; i++) {
137 | setTimeout(
138 | () => {
139 | // console.debug("z anim tick");
140 | this.z -= 1;
141 | },
142 | easeOutCirc(i / c) * 500,
143 | );
144 | }
145 |
146 | for (let i = 0; i < 30; i++) {
147 | setTimeout(
148 | () => {
149 | // console.debug("rot anim tick");
150 | this.r += 1;
151 | },
152 | easeOutCirc(i / 10) * 500,
153 | );
154 | }
155 | };
156 |
157 | setInterval(() => {
158 | // console.debug("polling inputs", keys)
159 |
160 | if (keydown("ArrowRight")) {
161 | this.r += 0.5;
162 | let orig = document.documentElement.style
163 | .getPropertyValue("--bgmoveX")
164 | .replace("px", "");
165 | document.documentElement.style.setProperty(
166 | "--bgmoveX",
167 | `${+orig - 2.5}px`,
168 | );
169 | }
170 | if (keydown("ArrowLeft")) {
171 | this.r -= 0.5;
172 | let orig = document.documentElement.style
173 | .getPropertyValue("--bgmoveX")
174 | .replace("px", "");
175 | document.documentElement.style.setProperty(
176 | "--bgmoveX",
177 | `${+orig + 2.5}px`,
178 | );
179 | }
180 |
181 | if (keydown("ArrowUp")) {
182 | this.y += keydown("Shift") ? this.speed * this.mult : this.speed;
183 | let orig = document.documentElement.style
184 | .getPropertyValue("--bgmoveY")
185 | .replace("px", "");
186 | document.documentElement.style.setProperty(
187 | "--bgmoveY",
188 | `${+orig + 0.35}px`,
189 | );
190 | }
191 | if (keydown("ArrowDown")) {
192 | this.y -= keydown("Shift") ? this.speed * this.mult : this.speed;
193 | let orig = document.documentElement.style
194 | .getPropertyValue("--bgmoveY")
195 | .replace("px", "");
196 | document.documentElement.style.setProperty(
197 | "--bgmoveY",
198 | `${+orig - 0.35}px`,
199 | );
200 | }
201 |
202 | if (keydown("w")) {
203 | let speed = keydown("Shift") ? this.speed * this.mult : this.speed;
204 | move(0, speed);
205 | // too buggy
206 | // let orig =
207 | // document.documentElement.style.getPropertyValue("--bgscale") || "1";
208 | // document.documentElement.style.setProperty(
209 | // "--bgscale",
210 | // `${+orig + speed * 0.00015}`
211 | // );
212 | }
213 |
214 | if (keydown("s")) {
215 | let speed = -(keydown("Shift") ? this.speed * this.mult : this.speed);
216 | move(0, speed);
217 | // let orig =
218 | // document.documentElement.style.getPropertyValue("--bgscale") || "1";
219 | // document.documentElement.style.setProperty(
220 | // "--bgscale",
221 | // `${+orig + speed * 0.00015}`
222 | // );
223 | }
224 |
225 | if (keydown("a")) {
226 | let speed = -(keydown("Shift") ? this.speed * this.mult : this.speed);
227 | move(speed, 0);
228 | let orig = document.documentElement.style
229 | .getPropertyValue("--bgmoveX")
230 | .replace("px", "");
231 | document.documentElement.style.setProperty(
232 | "--bgmoveX",
233 | `${+orig - speed * 0.35}px`,
234 | );
235 | }
236 |
237 | if (keydown("d")) {
238 | let speed = keydown("Shift") ? this.speed * this.mult : this.speed;
239 | move(speed, 0);
240 | let orig = document.documentElement.style
241 | .getPropertyValue("--bgmoveX")
242 | .replace("px", "");
243 | document.documentElement.style.setProperty(
244 | "--bgmoveX",
245 | `${+orig - speed * 0.35}px`,
246 | );
247 | }
248 | });
249 |
250 | const move = (x: number, z: number) => {
251 | // a bit more complex than neccesary because i'm bad at math
252 | const vel = -Math.hypot(x, z);
253 | const r = Math.atan2(z, x);
254 | const ang = this.r * -(Math.PI / 180) + r + Math.PI / 2;
255 |
256 | this.z += Math.cos(ang) * vel;
257 | this.x += Math.sin(ang) * vel;
258 | };
259 |
260 | return (
261 |
262 |
263 |
264 | arrow_back back to
265 | sanity
266 |
267 |
268 | {
271 | this.speed = numberInput("Enter new speed", this.speed);
272 | }}
273 | >
274 | {use`speed (${this.speed})`}
275 |
276 | v * 10)}
282 | on:change={() => {
283 | this.speed =
284 | +(document.getElementById("speed") as HTMLInputElement).value /
285 | 10;
286 | }}
287 | />
288 | {
290 | this.x = numberInput("Enter new position", this.x);
291 | }}
292 | >
293 | x: {use(this.x, (v) => v.toFixed(2))}
294 |
295 | {
297 | this.y = numberInput("Enter new position", this.y);
298 | }}
299 | >
300 | y: {use(this.y, (v) => v.toFixed(2))}
301 |
302 | {
304 | this.z = numberInput("Enter new position", this.z);
305 | }}
306 | >
307 | z: {use(this.z, (v) => v.toFixed(2))}
308 |
309 | {
311 | this.r = numberInput("Enter new position", this.r);
312 | }}
313 | >
314 | r: {use(this.r, (v) => v.toFixed(2))}
315 |
316 |
317 | {use(store.playMusic, (v) => (
318 | {
320 | store.playMusic = !store.playMusic;
321 | store.playMusic !== false
322 | ? document.dispatchEvent(new Event("music-restart"))
323 | : document.dispatchEvent(new Event("end-music"));
324 | }}
325 | >
326 |
327 | {v !== false ? "volume_up" : "volume_off"}
328 |
329 |
330 | ))}
331 |
332 |
337 |
342 |
351 |
352 | my work
353 |
354 |
355 |
356 |
364 |
365 |
366 |
374 |
375 |
376 |
385 |
386 |
387 |
388 |
389 |
399 |
400 |
401 |
409 |
410 | Blog
411 |
416 |
417 |
418 |
419 |
424 |
425 |
435 |
436 |
437 |
438 |
439 |
440 | );
441 | };
442 |
--------------------------------------------------------------------------------
/src/3DSite/ThreeDeeInfo.tsx:
--------------------------------------------------------------------------------
1 | import "dreamland";
2 | import { DesignPhilosophy } from "../SiteContent";
3 |
4 | export const ThreeDeeInfo: Component<{}, {}> = function () {
5 | return (
6 |
7 | about the 3d view!
8 | quick start guide
9 |
10 | use WASD to move
11 | use the left/right arrow keys to rotate the camera
12 | use the up/down arrow keys to move up and down
13 |
14 | check behind you to see my blog!
15 | how i did it
16 |
17 | the 3d effects are done purely with css 3d transforms! no webgl, canvas
18 | elements, smoke, or mirrors. i use a js framework called{" "}
19 |
20 | dreamland.js
21 | {" "}
22 | for basic reactivity, and to make development easier. you can check out
23 | the source of this page{" "}
24 |
28 | here
29 |
30 | !
31 |
32 | FAQ
33 | Q: why?
34 | A: because it's cool :3
35 |
36 | Q: why can't I click any links?
37 |
38 | A: you are using firefox. the firefox devs (in their infinite wisdom)
39 | refuse to implement modern standards correctly. please just use chrome.
40 |
41 |
42 | Q: this is so cool, why isn't it the default view?
43 |
44 | A: it's an accessibility nightmare, and doesn't even work right on most
45 | browsers (thanks mozilla). also, it's totally broken on phones! (i'm
46 | just too lazy to implement mobile controls :P)
47 |
48 |
49 | Q: where'd you get the idea?
50 |
51 | i was mainly inspired by{" "}
52 |
53 | velzie's website
54 |
55 | , which pulls off something similar. i actually used some of his code
56 | for this site, so it wouldn't be possible without him.
57 |
58 |
59 |
60 |
61 | );
62 | };
63 |
--------------------------------------------------------------------------------
/src/App.tsx:
--------------------------------------------------------------------------------
1 | console.log(
2 | "%c\n hello! :3c ",
3 | 'font-family: "IBM Plex Mono", ui-monospace, monospace;font-weight: 900; font-size: 50px;color: #f38ba8; text-shadow: -2px -2px 0 #fab387 , -4px -4px 0 #f9e2af , -6px -6px 0 #a6e3a1 , -8px -8px 0 #94e2d5 , -10px -10px 0 #89b4fa , -12px -12px 0 #b4befe , -14px -14px 0 #cba6f7',
4 | );
5 |
6 | import "dreamland";
7 | import { ThreeDeeApp } from "./3DSite/ThreeDeeApp.tsx";
8 | import ProjectCardDetails from "./Project.ts";
9 | import { ProjectList } from "./ProjectCard.tsx";
10 | import { projects } from "./Projects.ts";
11 | import { ClickWall } from "./3DSite/ClickWall.tsx";
12 | import { DarkReaderWarning } from "./DarkReaderWarning.tsx";
13 | import { sharedCSS, articleCSS } from "./CommonCSS.tsx";
14 | import { updatePage } from "./Themes";
15 | import { Intro, SiteMap, DesignPhilosophy } from "./SiteContent.tsx";
16 | import { convertRemToPixels } from "./Utils.ts";
17 | import { Footer } from "./Footer.tsx";
18 | import { Nav, TabBar } from "./Navigation.tsx";
19 | import { LatestToot } from "./LatestToot.tsx";
20 | import { oled } from "./Themes";
21 | // import { Cursor } from "./Cursor.tsx";
22 |
23 | // MARK: THEMING
24 | export let store = $store(
25 | {
26 | theme: oled,
27 | playMusic: false,
28 | },
29 | { ident: "userOptions", backing: "localstorage", autosave: "auto" },
30 | );
31 |
32 | export let globalState = $state({
33 | freakyMode: false,
34 | });
35 |
36 | const App: Component<
37 | {},
38 | {
39 | rotation: number;
40 | projects: ProjectCardDetails[];
41 | prevMouseX: number;
42 | prevMouseY: number;
43 | prevX: number;
44 | prevY: number;
45 | timeout: boolean;
46 | selectedTab: number;
47 | elements: Element[];
48 | }
49 | > = function () {
50 | this.prevMouseX = 0;
51 | this.prevMouseY = 0;
52 | this.prevX = 0;
53 | this.prevY = 0;
54 | this.projects = projects;
55 | this.rotation = 0;
56 | this.timeout = false;
57 | this.selectedTab = 0;
58 | this.elements = [
59 | ,
60 | ,
64 | // ,
65 |
66 |
latest post
67 |
68 | ,
69 | ,
70 | ,
71 | ];
72 | this.css = `
73 | // background: var(--crust);
74 | color: var(--text);
75 | font-family: var(--font-body);
76 | margin: 0;
77 | padding: 0;
78 | display: flex;
79 | flex-direction: column;
80 | align-items: center;
81 | justify-content: flex-start;
82 | // height: 100vh;
83 | max-width: 100vw;
84 | overflow-x: hidden;
85 | margin-bottom: 1.5rem;
86 |
87 | #content {
88 | background: var(--crust);
89 | width: min(100vw, max(60vw, 800px));
90 | height: 60vh;
91 | height: min-content;
92 | border-radius: 0 0 1.2rem 1.2rem;
93 | }
94 |
95 | #mainarticle {
96 | height: 100%;
97 | overflow: hidden;
98 | transition: 0.35s, opacity 0.15s;
99 | transition-timing-function: ease;
100 | }
101 |
102 | #content > *:not(#tabs) {
103 | padding-inline: 1rem;
104 | }
105 |
106 | #mainarticle.transparent {
107 | opacity: 0;
108 | transition: 0.35s, opacity 0.15s;
109 | transition-timing-function: ease;
110 | }
111 |
112 | footer {
113 | padding-bottom: 1rem;
114 | }
115 | `;
116 |
117 | function updateSize() {
118 | document.getElementById("mainarticle")!.style.height =
119 | document
120 | .getElementById("mainarticle")!
121 | .children[0]!.getBoundingClientRect().height +
122 | convertRemToPixels(1) +
123 | "px";
124 | }
125 |
126 | setTimeout(() => {
127 | // console.warn(document.getElementById("content")!.getBoundingClientRect().height);
128 | // console.warn(document.getElementById("mainarticle")!.getBoundingClientRect().height);
129 | updateSize();
130 |
131 | document.querySelector("main")?.dispatchEvent(
132 | new MouseEvent("move", {
133 | clientX: window.innerWidth,
134 | clientY: window.innerHeight,
135 | }),
136 | );
137 | // console.warn(document.getElementById("content")!.getBoundingClientRect().height);
138 | // console.warn(document.getElementById("mainarticle")!.getBoundingClientRect().height);
139 | }, 1);
140 |
141 | window.addEventListener("resize", () => {
142 | updateSize();
143 | });
144 |
145 | document.addEventListener("force-tab-resize", () => {
146 | updateSize();
147 | });
148 |
149 | document.addEventListener("pointermove", (e: PointerEvent) => {
150 | // i feel like this is way more complicated than it needs to be
151 | // console.debug(e.clientX, e.clientY);
152 | if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) {
153 | console.info("user prefers less motion");
154 | return;
155 | }
156 | const offsetX = this.prevMouseX - e.clientX;
157 | const offsetY = this.prevMouseY - e.clientY;
158 | // console.debug(offsetX, offsetY);
159 | const x = this.prevX - offsetX * 0.06;
160 | const y = this.prevY - offsetY * 0.06;
161 | // console.debug(x, y);
162 | document.documentElement.style.setProperty("--bgmoveX", x + "px");
163 | document.documentElement.style.setProperty("--bgmoveY", y + "px");
164 | this.prevMouseX = e.clientX;
165 | this.prevMouseY = e.clientY;
166 | this.prevX = x;
167 | this.prevY = y;
168 | });
169 |
170 | return (
171 |
175 | freak ? "Papyrus, cursive!important" : "var(--font-body)",
176 | ),
177 | }}
178 | >
179 |
180 |
181 |
191 |
192 | {use(this.selectedTab, (tab) => this.elements[tab])}
193 |
194 |
195 |
196 |
197 |
198 | );
199 | };
200 |
201 | // MARK: WINDOW LOAD
202 | window.addEventListener("load", async () => {
203 | document.addEventListener("keydown", (e) => {
204 | if (e.key === "Escape") {
205 | e.preventDefault();
206 | document.querySelectorAll(".popup").forEach((popup) => {
207 | popup.classList.add("transparent");
208 | setTimeout(() => {
209 | popup.remove();
210 | }, 200);
211 | });
212 | }
213 | });
214 |
215 | let params = new URL(window.location.href).searchParams;
216 | console.debug(params);
217 | if (params.has("higherdimension")) {
218 | let app;
219 | try {
220 | app = ;
221 | } catch (e) {
222 | (document.querySelector(".no-js")! as HTMLElement).style.display =
223 | "block";
224 | document.body.style.margin = "2%";
225 | return;
226 | }
227 | let audio: HTMLAudioElement = new Audio("/epic.ogg");
228 | audio.loop = true;
229 |
230 | document.addEventListener("end-music", () => {
231 | audio.pause();
232 | });
233 |
234 | document.addEventListener("music-restart", () => {
235 | audio.play();
236 | });
237 |
238 | // const audioCtx = new AudioContext();
239 | // const analyser = audioCtx.createAnalyser();
240 |
241 | // const source = audioCtx.createMediaElementSource(audio);
242 | // console.debug(source);
243 | // source.connect(analyser).connect(audioCtx.destination);
244 | // console.debug(source);
245 |
246 | if (store.playMusic !== false) {
247 | console.info("music start");
248 | audio.play().catch((e) => {
249 | console.error("could not start audio: " + e);
250 | document.body.appendChild( );
251 | return;
252 | });
253 | // audioCtx.resume();
254 | }
255 |
256 | document.getElementById("app")!.replaceWith(app);
257 | document.body.classList.add("cool");
258 | } else {
259 | let app;
260 | try {
261 | app = ;
262 | } catch (e) {
263 | (document.querySelector(".no-js")! as HTMLElement).style.display =
264 | "block";
265 | document.body.style.margin = "2%";
266 | return;
267 | }
268 | let sc = document.createElement("script");
269 | sc.src = "/oneko.js";
270 | document.body.appendChild(sc);
271 | document.getElementById("app")!.replaceWith(app);
272 |
273 | var konamiCurrent = 0;
274 | var konamiCode = [
275 | "ArrowUp",
276 | "ArrowUp",
277 | "ArrowDown",
278 | "ArrowDown",
279 | "ArrowLeft",
280 | "ArrowRight",
281 | "ArrowLeft",
282 | "ArrowRight",
283 | "b",
284 | "a",
285 | ];
286 |
287 | document.documentElement.addEventListener("keydown", (e: KeyboardEvent) => {
288 | console.debug(e.key);
289 |
290 | if (e.key === konamiCode[konamiCurrent]) {
291 | console.debug("match");
292 | document.getElementById("k" + konamiCurrent)?.classList.add("active");
293 | e.preventDefault();
294 | konamiCurrent++;
295 |
296 | if (konamiCurrent === konamiCode.length) {
297 | konamiCurrent = 0;
298 | window.location.href =
299 | new URL(window.location.href).origin + "/?higherdimension";
300 | }
301 | } else {
302 | konamiCurrent = 0;
303 | for (let i = 0; i < konamiCode.length; i++) {
304 | document.getElementById("k" + i)?.classList.remove("active");
305 | }
306 | }
307 | });
308 | }
309 |
310 | updatePage();
311 |
312 | // document.body.appendChild( );
313 |
314 | setInterval(() => {
315 | if (
316 | document.documentElement.getAttribute("data-darkreader-mode") ||
317 | document.documentElement.getAttribute("data-darkreader-scheme")
318 | ) {
319 | document.body.appendChild( );
320 | }
321 | }, 1000);
322 |
323 | const fnt = new FontFace(
324 | "Material Symbols Rounded",
325 | "url(https://fonts.gstatic.com/s/materialsymbolsrounded/v181/syl0-zNym6YjUruM-QrEh7-nyTnjDwKNJ_190FjpZIvDmUSVOK7BDB_Qb9vUSzq3wzLK-P0J-V_Zs-QtQth3-jOcbTCVpeRL2w5rwZu2rIelXxc.woff2)",
326 | );
327 | document.fonts.add(fnt);
328 | fnt.load(); // async load the font to prevent really wanky shit when something that uses it first appears
329 | });
330 |
--------------------------------------------------------------------------------
/src/CommonCSS.tsx:
--------------------------------------------------------------------------------
1 | import "dreamland";
2 |
3 | export const articleCSS = css`
4 | width: 100%;
5 | ul {
6 | list-style-type: circle;
7 | padding-inline-start: 2rem;
8 | }
9 |
10 | ul ul {
11 | list-style-type: "→ ";
12 | padding-inline-start: 2rem;
13 | }
14 | `;
15 |
16 | export const sharedCSS = css`
17 | a {
18 | text-decoration: none!important;
19 | }
20 |
21 | a:not(:has(img)) {
22 | filter: drop-shadow(0 0 0px transparent);
23 | transition: 0.25s ease filter;
24 |
25 | &:not(nav a) {
26 | border-bottom: 1px dotted var(--accent);
27 | }
28 |
29 | &:hover {
30 | /* border-bottom-style: solid; */
31 | filter: drop-shadow(0 0 4px var(--accent)) brightness(105%) contrast(110%);
32 | transition: 0.25s ease filter;
33 | }
34 |
35 | &:active {
36 | filter: drop-shadow(0 0 0px var(--accent)) brightness(95%) contrast(90%);
37 | transition: 0.25s ease filter;
38 | }
39 | }
40 |
41 | a,
42 | a:visited:hover {
43 | color: var(--accent);
44 | transition: color 0.1s;
45 | }
46 |
47 | a:visited {
48 | color: color-mix(in srgb, var(--accent) 70%, var(--base) 30%) !;
49 | }
50 |
51 | h1,
52 | h2:not(nav h2) {
53 | font-family: var(--font-serif);
54 | margin-top: 0.1rem;
55 | margin-bottom: 0.6rem;
56 | }
57 |
58 | h1 {
59 | font-weight: normal;
60 | font-size: 2rem;
61 | }
62 |
63 | h2 {
64 | font-weight: lighter;
65 | font-size: 1.5rem;
66 | }
67 |
68 | h3 {
69 | font-weight: lighter;
70 | }
71 |
72 | p,
73 | li {
74 | margin-block: 0.25rem;
75 | line-height: 1.5;
76 | }
77 |
78 | @media (prefers-reduced-motion: reduce) {
79 | .card:hover,
80 | .card:focus,
81 | .card:focus-visible,
82 | .card:active,
83 | .card:active:focus,
84 | nav a {
85 | transform: scale(1) !important;
86 | }
87 |
88 | .popup .inner {
89 | transition: opacity 0.4s !important;
90 | }
91 | }
92 |
93 | .card:focus kbd,
94 | .card:focus-visible kbd {
95 | opacity: 1;
96 | transition: opacity 0.2s;
97 | }
98 |
99 |
100 | * {
101 | outline-color: #cba6f7;
102 | outline-offset: 2px;
103 | }
104 |
105 | subt {
106 | color: var(--subtext0);
107 | }
108 |
109 | kbd {
110 | font-size: 0.85rem;
111 | /* margin: 0.5rem; */
112 | font-family: var(--font-mono);
113 | color: var(--subtext0);
114 | border: 1px solid var(--subtext0);
115 | padding: 0.15rem 0.6rem;
116 | border-radius: 0.3rem;
117 | }
118 |
119 | @media (orientation: portrait) {
120 | display: initial !important;
121 | width: 100vw;
122 |
123 | #theme-name {
124 | display: none;
125 | }
126 |
127 | #content,
128 | nav {
129 | width: 100vw !important;
130 | }
131 |
132 | .popup .inner {
133 | width: max(100%, 100vw) !important;
134 | height: max(100%, 100vh) !important;
135 | transition: 0.4s cubic-bezier(0.3, 1.2, 0.4, 1);
136 | }
137 |
138 | .popup .inner,
139 | .popup .head {
140 | border-radius: 0;
141 | }
142 |
143 | .popup .inner article {
144 | height: max(100%, 100vh);
145 | }
146 |
147 | .popup .inner .article-inner {
148 | flex-direction: column;
149 | align-items: center;
150 | }
151 |
152 | /* .popup .inner article img {
153 | width: 90vw;
154 | max-width: initial;
155 | height: auto;
156 | justify-self: center;
157 | } */
158 | }
159 |
160 | subt {
161 | color: var(--subtext0);
162 | font-size: 0.8rem;
163 | line-height: 1rem;
164 | }
165 |
166 | subt kbd {
167 | font-size: 0.7rem;
168 | }
169 |
170 | pre,
171 | code {
172 | font-size: 0.9rem;
173 | font-family: var(--font-mono);
174 | background: var(--base);
175 | }
176 |
177 | code {
178 | border-radius: 0.3rem;
179 | padding-inline: 0.5rem;
180 | padding-block: 0.15rem;
181 | }
182 |
183 | pre {
184 | padding: 1rem;
185 | border-radius: 0.6rem;
186 | overflow-x: auto;
187 | }
188 |
189 | // h1,
190 | // h2,
191 | // h3 {
192 | // font-family: var(--font-display);
193 | // }
194 |
195 | h2 {
196 | font-size: 1.6rem;
197 | margin-bottom: 0;
198 | margin-top: 0.1rem;
199 | }
200 |
201 | // nav h2 {
202 | // font-size: 1.5rem;
203 | // }
204 |
205 | // #content {
206 | // padding-inline: 1rem;
207 | // }
208 | `;
209 |
--------------------------------------------------------------------------------
/src/Cursor.tsx:
--------------------------------------------------------------------------------
1 | import "dreamland"
2 |
3 | export const Cursor: Component<{}, { x: number; y: number }> = function () {
4 | this.x = 0
5 | this.y = 0
6 |
7 | this.mount = () => {
8 | document.addEventListener("mousemove", (e) => {
9 | this.x = e.clientX
10 | this.y = e.clientY
11 | })
12 | }
13 |
14 | this.css = `
15 | position: fixed;
16 | top: 0;
17 | left: 0;
18 | pointer-events: none;
19 | z-index: 10000;
20 | width: 20px;
21 | height: 20px;
22 | border-radius: 50%;
23 | backdrop-filter: invert(1);
24 | translate: -10px -10px;
25 | display: flex;
26 | align-items: center;
27 | justify-content: center;
28 |
29 | span {
30 | filter: invert(1);
31 | }
32 |
33 | `
34 |
35 | return (
36 |
37 | +
38 |
39 | )
40 | }
--------------------------------------------------------------------------------
/src/DarkReaderWarning.tsx:
--------------------------------------------------------------------------------
1 | import "dreamland";
2 |
3 | export const DarkReaderWarning: Component<{}, {}> = function () {
4 | this.mount = () => {
5 | setInterval(() => {
6 | if (
7 | !document.documentElement.getAttribute("data-darkreader-mode") ||
8 | !document.documentElement.getAttribute("data-darkreader-scheme")
9 | ) {
10 | this.root.remove();
11 | }
12 | });
13 | };
14 |
15 | function ctpRed(): string {
16 | switch (document.body.classList[0]) {
17 | case "Mocha":
18 | return "#f38ba8";
19 | case "Macchiato":
20 | return "#ed8796";
21 | case "Frappe":
22 | return "#e78284";
23 | case "Latte":
24 | return "#d20f39";
25 | default:
26 | return "#f00";
27 | }
28 | }
29 |
30 | this.css = `
31 | position: fixed;
32 | bottom: 0;
33 | right: 0;
34 | background: var(--surface0);
35 | color: var(--text);
36 | padding: 0.5rem 1rem;
37 | font-family: var(--font-mono);
38 | font-size: 0.8rem;
39 | z-index: 1000;
40 | display: flex;
41 | align-items: center;
42 | justify-content: center;
43 | gap: 0.75rem;
44 | border-top-left-radius: 0.75rem;
45 |
46 | span {
47 | color: ${ctpRed()};
48 | }
49 |
50 | `;
51 |
52 | return (
53 |
54 |
warning {" "}
55 |
Dark Reader breaks this site.
56 |
Please disable it.
57 |
58 | );
59 | };
60 |
--------------------------------------------------------------------------------
/src/IsMobile.ts:
--------------------------------------------------------------------------------
1 | const mobileRE: RegExp =
2 | /(android|bb\d+|meego).+mobile|armv7l|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series[46]0|samsungbrowser.*mobile|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i;
3 | const notMobileRE: RegExp = /CrOS/;
4 |
5 | const tabletRE = /android|ipad|playbook|silk/i;
6 |
7 | export default function isMobile(opts: { ua?: string; tablet?: boolean; featureDetect?: boolean } = {}) {
8 | let ua = opts.ua;
9 | if (!ua && typeof navigator !== "undefined") ua = navigator.userAgent;
10 | // if (ua && ua.headers && typeof ua.headers["user-agent"] === "string") {
11 | // ua = ua.headers["user-agent"];
12 | // }
13 | if (typeof ua !== "string") return false;
14 |
15 | let result =
16 | (mobileRE.test(ua) && !notMobileRE.test(ua)) ||
17 | (!!opts.tablet && tabletRE.test(ua));
18 |
19 | if (
20 | !result &&
21 | opts.tablet &&
22 | opts.featureDetect &&
23 | navigator &&
24 | navigator.maxTouchPoints > 1 &&
25 | ua.indexOf("Macintosh") !== -1 &&
26 | ua.indexOf("Safari") !== -1
27 | ) {
28 | result = true;
29 | }
30 |
31 | return result;
32 | }
--------------------------------------------------------------------------------
/src/LargeProjectView.tsx:
--------------------------------------------------------------------------------
1 | import "dreamland";
2 | import ProjectCardDetails from "./Project.ts";
3 | import isMobile from "./IsMobile.ts";
4 |
5 | // TODO: Use
6 | export const LargeProjectView: Component<{ project: ProjectCardDetails }, {}> =
7 | function () {
8 | this.mount = () => {
9 | setTimeout(() => {
10 | this.root.classList.remove("transparent");
11 | }, 1);
12 | };
13 |
14 | this.css = `
15 | position: fixed;
16 | top: 0;
17 | left: 0;
18 | right: 0;
19 | bottom: 0;
20 | z-index: 100;
21 | width: 100vw;
22 | height: 100vh;
23 | transform: translateZ(100px);
24 |
25 | transition: 0.2s cubic-bezier(0.3, 0, 0.6, 1);
26 |
27 | @media (orientation: landscape) {
28 | .inner {
29 | aspect-ratio: 800 / 565;
30 | }
31 | }
32 |
33 | .inner {
34 | background: var(--base);
35 | // background-image: url(${this.project.img});
36 | min-width: 400px;
37 | width: max(55vw, 50rem);
38 | height: 60vh;
39 | position: absolute;
40 | top: 50%;
41 | left: 50%;
42 | border-radius: 1.25rem;
43 | transform: translateX(-50%) translateY(-50%);
44 | z-index: 100;
45 | border: 0.25px solid var(--surface0);
46 | overflow: hidden;
47 | }
48 |
49 | img {
50 | width: 100%;
51 | height: 100%;
52 | position: absolute;
53 | top: 0;
54 | left: 0;
55 | right: 0;
56 | bottom: 0;
57 | user-select: none;
58 | -webkit-user-drag: none;
59 | -webkit-user-select: none;
60 | object-fit: cover;
61 | z-index: 1;
62 | }
63 |
64 | .inner::before {
65 | content: "";
66 | position: absolute;
67 | top: 0;
68 | left: 0;
69 | width: 100%;
70 | height: 100%;
71 | backdrop-filter: blur(8px);
72 | mask-image: linear-gradient(rgba(0, 0, 0, 0.2) 30%, rgb(0, 0, 0, 1) 92%);
73 | background: linear-gradient(rgba(0, 0, 0, 0.6), rgba(0, 0, 0, 0.8) 95%);
74 | z-index: 2;
75 | pointer-events: none;
76 | }
77 |
78 | #title,p {
79 | filter: drop-shadow(0 0 30px rgb(0, 0, 0));
80 | }
81 |
82 | #title {
83 | font-size: 4rem;
84 | padding-inline: 1.5rem;
85 | font-weight: bold;
86 | text-overflow: ellipsis;
87 | overflow: hidden;
88 | font-family: var(--font-serif);
89 | line-height: 1em;
90 | padding-bottom: 0.25em;
91 | margin-bottom: -0.1em;
92 | width: 100%;
93 | }
94 |
95 | button {
96 | user-select: none;
97 | -webkit-user-drag: none;
98 | -webkit-user-select: none;
99 | width: 36px;
100 | height: 36px;
101 | border-radius: 38px;
102 | background: color-mix(in srgb, var(--surface2) 45%, transparent)!important;
103 | transition: background 0.15s ease;
104 | backdrop-filter: blur(32px);
105 | cursor: pointer;
106 |
107 | overflow: hidden;
108 | transition: transform 0.3s ease;
109 |
110 | .label {
111 | font-size: 12px;
112 | margin-left: 2px;
113 | width: 0px;
114 | overflow: hidden;
115 | transition: width 0.3s ease;
116 | }
117 | }
118 |
119 | button:hover {
120 | background: color-mix(in srgb, var(--surface2) 60%, transparent)!important;
121 | }
122 |
123 | // button:hover .label {
124 | // width: 48px;
125 | // }
126 |
127 | article {
128 | overflow: scroll;
129 | display: grid;
130 | place-items: center;
131 | height: 60vh;
132 | }
133 |
134 | .article-inner {
135 | overflow: scroll;
136 | position: relative;
137 | width: 100%;
138 | height: calc(100% - 7rem);
139 | display: flex;
140 | flex-direction: column;
141 | align-items: flex-start;
142 | overflow: scroll;
143 | align-self: flex-end;
144 | justify-self: center;
145 | z-index: 3;
146 | padding-bottom: 1rem;
147 | }
148 |
149 | .head {
150 | display: flex;
151 | flex-direction: row;
152 | align-items: center;
153 | justify-content: space-between;
154 | width: 100%;
155 | height: 6rem;
156 | position: fixed;
157 | top: -1px;
158 | left: 0;
159 | right: 0;
160 | // background: var(--mantle);
161 | border-radius: 1.25rem 1.25rem 0 0;
162 | margin: 0;
163 | z-index: 1000;
164 | }
165 |
166 | .head > * {
167 | margin: 1.5rem;
168 | }
169 |
170 | .desc {
171 | align-self: flex-start;
172 | font-size: 1.25rem;
173 | margin-inline: 1rem;
174 | }
175 |
176 | .desc p {
177 | margin-left: 0.5rem;
178 | margin-bottom: 1.25rem;
179 | }
180 |
181 | button {
182 | appearance: none;
183 | background: none;
184 | border: none;
185 | // width: 25px;
186 | // height: 25px;
187 | color: var(--text);
188 | display: flex;
189 | align-items: center;
190 | }
191 |
192 | .popup-bg {
193 | transition: 0.2s cubic-bezier(0.3, 0, 0.6, 1);
194 | background: rgba(17, 17, 27, 0.4);
195 | position: fixed;
196 | top: 0;
197 | left: 0;
198 | right: 0;
199 | bottom: 0;
200 | z-index: 90;
201 | width: 100vw;
202 | height: 100vh;
203 | backdrop-filter: blur(1.5px);
204 | -webkit-backdrop-filter: blur(1.5px);
205 | }
206 |
207 | kbd {
208 | margin-right: 0.65rem;
209 | }
210 |
211 | .link {
212 | color: var(--text)!important;
213 |
214 | background: color-mix(in srgb, var(--surface0) 60%, transparent)!important;
215 | backdrop-filter: blur(30px);
216 | text-decoration: none;
217 | cursor: pointer;
218 |
219 | border: none!important;
220 |
221 | font-size: 1.2rem;
222 |
223 | border-radius: 0.75rem;
224 | padding: 0.5rem;
225 |
226 | .material-symbols-rounded {
227 | font-size: 1.6rem;
228 | margin-right: 0.5rem;
229 | }
230 |
231 | .link-inner {
232 | display: flex;
233 | align-items: center;
234 | }
235 |
236 | display: flex;
237 | align-items: center;
238 | justify-content: center;
239 |
240 | border: 0.1px solid var(--overlay1)!important;
241 |
242 | transition: color 0.2s;
243 | }
244 |
245 | .link:hover {
246 | transition: color 0.2s;
247 | color: var(--accent);
248 | }
249 |
250 | p.link {
251 | color: var(--subtext0);
252 | //font-style: italic;
253 | border-style: dashed;
254 | cursor: not-allowed;
255 | }
256 |
257 | p.link:hover {
258 | color: var(--subtext0);
259 | }
260 |
261 | .links {
262 | display: grid;
263 | grid-template-columns: repeat(auto-fit, minmax(50%, 1fr));
264 | gap: 0.5rem;
265 | }
266 |
267 | &.transparent .inner {
268 | top: 100vw;
269 | transition: 0.2s ease-in-out;
270 | }
271 |
272 | &.transparent
273 | {
274 | transition: 0.2s cubic-bezier(0.3, 0, 0.6, 1);
275 | }
276 |
277 | .inner {
278 | transition: 0.4s cubic-bezier(0.3, 1.2, 0.4, 1);
279 | }
280 |
281 | &.transparent {
282 | opacity: 0;
283 | pointer-events: none;
284 | }
285 |
286 | &.transparent .popup-bg {
287 | transition: 0.2s cubic-bezier(0.3, 0, 0.6, 1);
288 | backdrop-filter: blur(0px);
289 | -webkit-backdrop-filter: blur(0px);
290 | background: rgba(0, 0, 0, 0);
291 | }
292 | `;
293 |
294 | return (
295 |
366 | );
367 | };
368 |
--------------------------------------------------------------------------------
/src/N64.tsx:
--------------------------------------------------------------------------------
1 | import 'dreamland'
2 | import isMobile from "./IsMobile.ts";
3 |
4 | export const MK64Frame: Component<{},{}> = function() {
5 | this.mount = () => {
6 | setTimeout(() => {
7 | this.root.classList.remove("transparent");
8 | }, 1);
9 | };
10 |
11 | this.css = `
12 | position: fixed;
13 | top: 0;
14 | left: 0;
15 | right: 0;
16 | bottom: 0;
17 | z-index: 100;
18 | width: 100vw;
19 | height: 100vh;
20 | transform: translateZ(100px);
21 |
22 | transition: 0.2s cubic-bezier(0.3, 0, 0.6, 1);
23 |
24 | .inner {
25 | background: var(--base);
26 | min-width: 400px;
27 | width: max(55vw, 50rem);
28 | height: 60vh;
29 | padding: 1rem;
30 | padding-top: 0;
31 | position: absolute;
32 | top: 50%;
33 | left: 50%;
34 | border-radius: 1.25rem;
35 | transform: translateX(-50%) translateY(-50%);
36 | z-index: 100;
37 | border: 0.25px solid var(--surface0);
38 | overflow: hidden;
39 | }
40 |
41 | img {
42 | width: auto;
43 | max-width: 35vw;
44 | height: 100%;
45 | border-radius: 1.25rem;
46 | user-select: none;
47 | -webkit-user-drag: none;
48 | -webkit-user-select: none;
49 | object-fit: cover;
50 | cursor: pointer;
51 | }
52 |
53 | #title {
54 | font-size: 2.25rem;
55 | margin-block: 0;
56 | font-weight: 600;
57 | text-overflow: ellipsis;
58 | overflow: hidden;
59 | white-space: nowrap;
60 | font-family: var(--font-serif);
61 | }
62 |
63 | button {
64 | user-select: none;
65 | -webkit-user-drag: none;
66 | -webkit-user-select: none;
67 | }
68 |
69 | article {
70 | overflow: scroll;
71 | display: grid;
72 | place-items: center;
73 | height: 60vh;
74 | }
75 |
76 | .article-inner {
77 | overflow: scroll;
78 | position: relative;
79 | width: 100%;
80 | height: calc(100% - 7rem);
81 | display: flex;
82 | flex-direction: row;
83 | align-items: flex-start;
84 | overflow: scroll;
85 | align-self: flex-end;
86 | justify-self: center
87 | }
88 |
89 | .head {
90 | display: flex;
91 | flex-direction: row;
92 | align-items: center;
93 | justify-content: space-between;
94 | width: 100%;
95 | height: 6rem;
96 | position: fixed;
97 | top: -1px;
98 | left: 0;
99 | right: 0;
100 | background: var(--mantle);
101 | border-radius: 1.25rem 1.25rem 0 0;
102 | margin: 0;
103 | z-index: 1000;
104 | }
105 |
106 | .head > * {
107 | margin: 1.5rem;
108 | }
109 |
110 | .desc {
111 | align-self: flex-start;
112 | font-size: 1.25rem;
113 | margin-inline: 1rem;
114 | }
115 |
116 | .desc p {
117 | margin-left: 0.5rem;
118 | margin-bottom: 1.25rem;
119 | }
120 |
121 | button {
122 | appearance: none;
123 | background: none;
124 | border: none;
125 | // width: 25px;
126 | // height: 25px;
127 | color: var(--text);
128 | display: flex;
129 | align-items: center;
130 | }
131 |
132 | .popup-bg {
133 | transition: 0.2s cubic-bezier(0.3, 0, 0.6, 1);
134 | background: rgba(17, 17, 27, 0.4);
135 | position: fixed;
136 | top: 0;
137 | left: 0;
138 | right: 0;
139 | bottom: 0;
140 | z-index: 90;
141 | width: 100vw;
142 | height: 100vh;
143 | backdrop-filter: blur(1.5px);
144 | -webkit-backdrop-filter: blur(1.5px);
145 | }
146 |
147 | kbd {
148 | margin-right: 0.65rem;
149 | }
150 |
151 | .link {
152 | color: var(--text)!important;
153 | background: var(--surface0);
154 | text-decoration: none;
155 | cursor: pointer
156 |
157 | font-size: 1.2rem;
158 |
159 | border-radius: 0.5rem;
160 | padding: 0.5rem;
161 |
162 | .material-symbols-rounded {
163 | font-size: 1.6rem;
164 | margin-right: 0.5rem;
165 | }
166 |
167 | .link-inner {
168 | display: flex;
169 | align-items: center;
170 | }
171 |
172 | display: flex;
173 | align-items: center;
174 | justify-content: center;
175 |
176 | border: 0.1px solid var(--overlay1);
177 |
178 | transition: color 0.2s;
179 | }
180 |
181 | .link:hover {
182 | transition: color 0.2s;
183 | color: var(--accent);
184 | }
185 |
186 | p.link {
187 | color: var(--subtext0);
188 | //font-style: italic;
189 | border-style: dashed;
190 | cursor: not-allowed;
191 | }
192 |
193 | p.link:hover {
194 | color: var(--subtext0);
195 | }
196 |
197 | .links {
198 | display: grid;
199 | grid-template-columns: repeat(auto-fit, minmax(50%, 1fr));
200 | gap: 0.5rem;
201 | }
202 |
203 | &.transparent .inner {
204 | top: 100vw;
205 | transition: 0.2s ease-in-out;
206 | }
207 |
208 | &.transparent
209 | {
210 | transition: 0.2s cubic-bezier(0.3, 0, 0.6, 1);
211 | }
212 |
213 | .inner {
214 | transition: 0.4s cubic-bezier(0.3, 1.2, 0.4, 1);
215 | }
216 |
217 | &.transparent {
218 | opacity: 0;
219 | pointer-events: none;
220 | }
221 |
222 | &.transparent .popup-bg {
223 | transition: 0.2s cubic-bezier(0.3, 0, 0.6, 1);
224 | backdrop-filter: blur(0px);
225 | -webkit-backdrop-filter: blur(0px);
226 | background: rgba(0, 0, 0, 0);
227 | }
228 | `;
229 |
230 | return (
231 |
262 | );
263 | }
264 |
--------------------------------------------------------------------------------
/src/Navigation.tsx:
--------------------------------------------------------------------------------
1 | import "dreamland";
2 | import { ThemePicker } from "./Themes";
3 | import { convertRemToPixels } from "./Utils";
4 |
5 | export const Nav: Component<
6 | {},
7 | { rotation: number; name: string; nameState: boolean }
8 | > = function () {
9 | this.rotation = 0;
10 | this.name = "BomberFish";
11 | this.nameState = false;
12 | this.css = `
13 | background: var(--base);
14 | justify-self: flex-start;
15 | z-index: 100;
16 | padding: 0.25em 1em;
17 | width: min(100vw, max(60vw, 800px));
18 | height: 3.75rem;
19 | margin: 0;
20 | display: -webkit-box;
21 | display: -webkit-flex;
22 | display: -moz-box;
23 | display: -ms-flexbox;
24 | display: flex;
25 | -webkit-box-orient: horizontal;
26 | -webkit-box-direction: normal;
27 | -webkit-flex-direction: row;
28 | -moz-box-orient: horizontal;
29 | -moz-box-direction: normal;
30 | -ms-flex-direction: row;
31 | flex-direction: row;
32 | -webkit-box-align: center;
33 | -webkit-align-items: center;
34 | -moz-box-align: center;
35 | -ms-flex-align: center;
36 | align-items: center;
37 |
38 | h2 {
39 | justify-self: flex-start;
40 | margin: 0;
41 | user-select: none;
42 | display: flex;
43 | align-items: flex-start;
44 | margin: 0!important;
45 | gap: 0.1rem;
46 | font-weight: normal !important;
47 | font-size: 1.75rem!important;
48 |
49 | /* Nintendo Switch-style 3d spinning text effect */
50 | & > span {
51 | animation: spin 5s cubic-bezier(0.37, 0, 0.63, 1) infinite;
52 |
53 | &:nth-of-type(1) {
54 | animation-delay: 0.7s;
55 | }
56 | &:nth-of-type(2) {
57 | animation-delay: 0.775s;
58 | }
59 | &:nth-of-type(3) {
60 | animation-delay: 0.85s;
61 | }
62 | &:nth-of-type(4) {
63 | animation-delay: 0.925s;
64 | }
65 | &:nth-of-type(5) {
66 | animation-delay: 1.0s;
67 | }
68 | &:nth-of-type(6) {
69 | animation-delay: 1.075s;
70 | }
71 | &:nth-of-type(7) {
72 | animation-delay: 1.15s;
73 | }
74 | &:nth-of-type(8) {
75 | animation-delay: 1.225s;
76 | }
77 | &:nth-of-type(9) {
78 | animation-delay: 1.3s;
79 | }
80 | &:nth-of-type(10) {
81 | animation-delay: 1.375s;
82 | }
83 | }
84 |
85 | @media (prefers-reduced-motion: reduce) {
86 | & > span {
87 | animation: none;
88 | }
89 | }
90 | }
91 |
92 | img {
93 | -webkit-border-radius: 100%;
94 | -moz-border-radius: 100%;
95 | border-radius: 100%;
96 | display: inline;
97 | margin-left: 0;
98 | margin-right: 0.4em;
99 | cursor: pointer;
100 | -webkit-transition: -webkit-transform 0.5s cubic-bezier(0.3, 0, 0.6, 1);
101 | transition: -webkit-transform 0.5s cubic-bezier(0.3, 0, 0.6, 1);
102 | -o-transition: -o-transform 0.5s cubic-bezier(0.3, 0, 0.6, 1);
103 | -moz-transition: transform 0.5s cubic-bezier(0.3, 0, 0.6, 1),
104 | -moz-transform 0.5s cubic-bezier(0.3, 0, 0.6, 1);
105 | transition: transform 0.5s cubic-bezier(0.3, 0, 0.6, 1);
106 | transition: transform 0.5s cubic-bezier(0.3, 0, 0.6, 1),
107 | -webkit-transform 0.5s cubic-bezier(0.3, 0, 0.6, 1),
108 | -moz-transform 0.5s cubic-bezier(0.3, 0, 0.6, 1),
109 | -o-transform 0.5s cubic-bezier(0.3, 0, 0.6, 1);
110 | -webkit-transform: rotate(0deg);
111 | -moz-transform: rotate(0deg);
112 | -ms-transform: rotate(0deg);
113 | -o-transform: rotate(0deg);
114 | transform: rotate(0deg);
115 | background: black;
116 | padding: 2px;
117 |
118 | width: 2.2rem;
119 | height: 2.2rem;
120 |
121 | user-select: none;
122 | -webkit-user-drag: none;
123 | -webkit-user-select: none;
124 | }
125 |
126 | #title {
127 | display: flex;
128 | align-items: center;
129 | justify-self: flex-start;
130 | font-family: var(--font-serif);
131 | font-weight: normal !important;
132 | font-size: 2rem!important;
133 | }
134 |
135 | subt {
136 | font-size: 0.875rem !important;
137 | font-family: var(--font-mono);
138 | margin-top: 0.3em;
139 | }
140 |
141 | #right {
142 | justify-self: flex-end;
143 | margin-left: auto;
144 | display: flex;
145 | align-items: center;
146 | gap: 0.5rem;
147 |
148 | & > a {
149 | text-decoration: none;
150 | transform: scale(1);
151 | color: var(--accent);
152 | font-size: 1rem;
153 | display: flex;
154 | align-items: center;
155 |
156 | user-select: none;
157 | -webkit-user-drag: none;
158 | -webkit-user-select: none;
159 | }
160 | }
161 |
162 | @media (orientation: portrait) {
163 | #bloglink-title {
164 | display: none;
165 | }
166 | }
167 |
168 | @keyframes spin {
169 | 0% {
170 | transform: rotate3d(0, 1, 0, 0deg);
171 | }
172 | 10% {
173 | transform: rotate3d(0, 1, 0, 359deg);
174 | }
175 | 100% {
176 | transform: rotate3d(0, 1, 0, 360deg);
177 | }
178 | }
179 | `;
180 | return (
181 |
182 |
183 | {
189 | e.preventDefault();
190 | console.log("click");
191 | this.rotation -= 1440;
192 | }}
193 | />
194 |
195 | b
196 | o
197 | m
198 | b
199 | e
200 | r
201 | f
202 | i
203 | s
204 | h
205 | (he/they)
206 |
207 |
208 |
209 |
210 |
217 |
218 |
219 | blog
220 |
221 |
222 |
223 |
224 | );
225 | };
226 |
227 | export const TabBar: Component<
228 | { tabs: string[]; tab?: number },
229 | { tabInternal: number }
230 | > = function () {
231 | this.tab = 0;
232 | this.tabInternal = 0;
233 | this.css = `
234 | margin-bottom: 1rem;
235 | padding-block: 0.5rem;
236 | overflow-x: auto;
237 | // background: var(--base);
238 |
239 | @keyframes bounce {
240 | 0%, 100% {
241 | transform: translateY(0.15rem);
242 | }
243 | 40%,60% {
244 | transform: translateY(-0.15rem);
245 | }
246 | }
247 |
248 | div {
249 | display: flex;
250 | justify-content: flex-start;
251 | gap: 1.5rem;
252 | width: 100%;
253 | margin-block: 0.25rem;
254 | // padding-inline: 0.5rem;
255 | }
256 |
257 | button, button.active, button:hover, button:focus, button:active {
258 | transition: all 0.35s cubic-bezier(0, 0.55, 0.45, 1)!important;
259 | }
260 |
261 | button {
262 | font-family: var(--font-display);
263 | font-weight: 500;
264 | font-size: 1.2rem;
265 |
266 | animation: bounce 1s cubic-bezier(0.2, 0, 0.8, 1) infinite;
267 |
268 | &:nth-of-type(7) {
269 | animation-delay: -0.1s;
270 | }
271 |
272 | &:nth-of-type(6) {
273 | animation-delay: -0.2s;
274 | }
275 |
276 | &:nth-of-type(5) {
277 | animation-delay: -0.3s;
278 | }
279 |
280 | &:nth-of-type(4) {
281 | animation-delay: -0.4s;
282 | }
283 |
284 | &:nth-of-type(3) {
285 | animation-delay: -0.5s;
286 | }
287 |
288 | &:nth-of-type(2) {
289 | animation-delay: -0.6s;
290 | }
291 |
292 | &:nth-of-type(1) {
293 | animation-delay: -0.7s;
294 | }
295 |
296 | white-space: nowrap;
297 |
298 | background: transparent;
299 | color: var(--text);
300 | padding: 0;
301 | padding-bottom: 1px;
302 | border: none;
303 | outline: none!important;
304 | cursor: pointer;
305 |
306 | user-select: none;
307 | -webkit-user-drag: none;
308 | -webkit-user-select: none;
309 |
310 | border-bottom: 3.25px solid transparent;
311 | border-radius: 0;
312 |
313 | font-weight: 500;
314 |
315 | color: var(--overlay1);
316 | filter: drop-shadow(0 0 10px transparent);
317 | scale: 1;
318 |
319 | &.selected {
320 | filter: drop-shadow(0 0 10px color-mix(in srgb, var(--accent) 70%, transparent));
321 | color: var(--text);
322 | padding-bottom: 1px;
323 | border-bottom-color: var(--accent);
324 | font-weight: 700;
325 | }
326 |
327 | &:hover:not(.selected),
328 | &:focus:not(.selected) {
329 | filter: drop-shadow(0 0 10px var(--overlay1));
330 | border-width: 2px;
331 | padding-bottom: 0.1em;
332 | border-bottom-color: var(--surface2);
333 | }
334 |
335 | &:hover:not(.selected) {
336 | font-weight: 350;
337 | color: var(--subtext0);
338 | }
339 |
340 | &:active:not(.selected) {
341 | scale: 0.95;
342 | font-weight: 250;
343 | border-width: 1.5px;
344 | }
345 |
346 | &:first-of-type {
347 | margin-left: 1rem;
348 | }
349 |
350 | &:last-of-type {
351 | margin-right: 1rem;
352 | }
353 | }
354 |
355 | @media (prefers-reduced-motion: reduce) {
356 | button {
357 | animation: none;
358 | }
359 | }
360 | `;
361 |
362 | return (
363 |
364 |
365 | {use(this.tabs, (tabs) =>
366 | tabs.map((tab, index) => (
367 | [
369 | // tab === index ? "active" : "",
370 | // ])}
371 | class:selected={use(this.tabInternal, (tabi) => tabi == index)}
372 | on:click={() => {
373 | if (this.tabInternal === index) return;
374 | this.tabInternal = index;
375 | document
376 | .getElementById("mainarticle")!
377 | .classList.add("transparent");
378 | if (
379 | !window.matchMedia("(prefers-reduced-motion: reduce)").matches
380 | ) {
381 | document.getElementById("mainarticle")!.style.height = "0px";
382 | }
383 | setTimeout(
384 | () => {
385 | this.tab = index;
386 | document.getElementById("mainarticle")!.style.height =
387 | document
388 | .getElementById("mainarticle")!
389 | .children[0]!.getBoundingClientRect().height +
390 | convertRemToPixels(1) +
391 | "px";
392 | document
393 | .getElementById("mainarticle")!
394 | .classList.remove("transparent");
395 | },
396 | window.matchMedia("(prefers-reduced-motion: reduce)").matches
397 | ? 150
398 | : 570,
399 | );
400 | }}
401 | >
402 | {tab}
403 |
404 | )),
405 | )}
406 |
407 |
408 | );
409 | };
410 |
--------------------------------------------------------------------------------
/src/Project.ts:
--------------------------------------------------------------------------------
1 | export default class ProjectCardDetails {
2 | img: string | undefined;
3 | title: string;
4 | blurb: string;
5 | year: number;
6 | largeDesc: string;
7 | links?: { name: string; url: string; icon?: string }[];
8 | featured?: boolean;
9 | featuredPosition?: number | undefined;
10 |
11 | constructor(
12 | imgURL: string | undefined,
13 | title: string,
14 | blurb: string,
15 | year: number,
16 | largeDesc: string,
17 | links?: { name: string; url: string; icon?: string }[],
18 | featured?: boolean,
19 | featuredPosition?: number | undefined,
20 | ) {
21 | this.img = imgURL;
22 | this.title = title;
23 | this.blurb = blurb;
24 | this.year = year;
25 | this.largeDesc = largeDesc;
26 | this.links = links;
27 | this.featured = featured;
28 | this.featuredPosition = featuredPosition;
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/ProjectCard.tsx:
--------------------------------------------------------------------------------
1 | import "dreamland";
2 | import ProjectCardDetails from "./Project";
3 | import { LargeProjectView } from "./LargeProjectView";
4 |
5 | export const ProjectCard: Component<{ detail: ProjectCardDetails }, {}> =
6 | function () {
7 | this.css = `
8 | background: var(--surface0);
9 | width: 100%;
10 | min-height: 280px;
11 | border-radius: 1rem!important;
12 | padding-bottom: 0.2rem;
13 | cursor: pointer;
14 | transform: scale(1);
15 | transition: 0.25s cubic-bezier(0, 0.55, 0.45, 1);
16 | --shadow-color: color-mix(in srgb, var(--accent) 30%, transparent);
17 | box-shadow: 0 0 0px var(--shadow-color);
18 | border: 1px dashed var(--overlay1);
19 |
20 | &:hover {
21 | transform: scale(1.02);
22 | transition: 0.25s cubic-bezier(0, 0.55, 0.45, 1);
23 | box-shadow: 0 0 30px var(--shadow-color);
24 | border-color: var(--accent);
25 | }
26 |
27 | &:focus,
28 | &:focus-visible {
29 | outline: none;
30 | border-color: var(--accent)!important;
31 | border-style: solid!important;
32 | transform: scale(1.05);
33 | transition: 0.25s cubic-bezier(0, 0.55, 0.45, 1);
34 | box-shadow: 0 0 20px var(--shadow-color);
35 | }
36 |
37 | &.active,
38 | &:active:focus {
39 | transform: scale(0.95);
40 | transition: 0.1s cubic-bezier(0, 0.55, 0.45, 1);
41 | }
42 |
43 | transform: translateZ(50px);
44 |
45 | .img-container {
46 | width: 100%;
47 | height: auto;
48 | aspect-ratio: 512 / 277;
49 | }
50 |
51 | img {
52 | user-select: none;
53 | -webkit-user-drag: none;
54 | -webkit-user-select: none;
55 | border-radius: 0.9rem;
56 | width: calc(100% - 1px);
57 | height: calc(100% - 1px);
58 | object-fit: cover;
59 | }
60 |
61 | .img-placeholder {
62 | display: flex;
63 | justify-content: center;
64 | align-items: center;
65 | width: calc(100% - 1px);
66 | height: calc(100% - 1px);
67 | border-radius: 0.9rem;
68 | background: var(--base);
69 | color: var(--subtext0);
70 | span {
71 | font-size: 3rem;
72 | }
73 | }
74 |
75 | .title {
76 | display: flex;
77 | align-items: center;
78 | margin-top: 0.2rem;
79 | font-family: var(--font-body);
80 | overflow: hidden;
81 | text-overflow: ellipsis;
82 | white-space: nowrap;
83 | font-family: 1rem;
84 | }
85 |
86 | p {
87 | margin: 0!important;
88 | margin-top: 0.025rem!important;
89 | }
90 |
91 | .title > span {
92 | font-size: 1.5rem;
93 | font-weight: 600;
94 | margin-right: 0.5rem;
95 | font-family: var(--font-serif);
96 | }
97 |
98 | .detail {
99 | margin: 1rem;
100 | margin-top: 0.1rem;
101 | }
102 |
103 | p {
104 | margin-top: 0.5rem;
105 | margin-bottom: 1rem;
106 | }
107 |
108 | kbd {
109 | position: absolute;
110 | right: 1rem;
111 | top: 75%;
112 | opacity: 0;
113 | transition: opacity 0.2s;
114 | }
115 | `;
116 |
117 | return (
118 | {
121 | document
122 | .querySelector("main")!
123 | .appendChild(
);
124 | (document.activeElement as HTMLElement)?.blur();
125 | }}
126 | on:keydown={(e: KeyboardEvent) => {
127 | if (e.key === "Enter") {
128 | this.root.classList.add("active");
129 | setTimeout(() => {
130 | var ptr = new PointerEvent("pointerup", {
131 | bubbles: true,
132 | cancelable: true,
133 | });
134 | this.root.dispatchEvent(ptr);
135 |
136 | this.root.classList.remove("active");
137 | }, 200);
138 | }
139 | }}
140 | tabindex="0"
141 | >
142 |
150 | {$if(
151 | this.detail.img != undefined,
152 |
,
159 |
160 | broken_image
161 |
,
162 | )}
163 |
164 |
165 |
166 | {this.detail.title}
167 | • ({this.detail.year})
168 |
169 |
{this.detail.blurb}
170 |
↩
171 |
172 |
173 | );
174 | };
175 |
176 | export const ProjectList: Component<{ projects: ProjectCardDetails[] }, {}> =
177 | function () {
178 | this.css = `
179 | .projects-group {
180 | display: grid;
181 | grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
182 | grid-gap: 2rem;
183 | place-items: center;
184 | place-content: center;
185 | width: calc(100% - 4rem);
186 | margin: 0 2rem;
187 | }
188 | `;
189 | return (
190 |
191 |
featured
192 |
193 | {use(this.projects, (projects) =>
194 | projects
195 | .filter((project) => project.featured)
196 | .sort((a, b) => (a.featuredPosition || 0) - (b.featuredPosition || 0))
197 | .map((project) =>
),
198 | )}
199 |
200 |
other
201 |
202 | {use(this.projects, (projects) =>
203 | projects
204 | .filter((project) => !project.featured)
205 | .map((project) =>
),
206 | )}
207 |
208 |
209 | );
210 | };
211 |
--------------------------------------------------------------------------------
/src/Projects.ts:
--------------------------------------------------------------------------------
1 | import ProjectCardDetails from "./Project";
2 |
3 | export const projects = [
4 | // new ProjectCardDetails(
5 | // "/proj-thumbnails/celeste.webp",
6 | // "Webshot",
7 | // "Port of OneShot to WebAssembly",
8 | // 2024,
9 | // "Webshot is a port of OneShot: World Machine Edition to WebAssembly. Like fez-wasm and Webleste, it leverages WebAssembly support in .NET and FNA to run the game in a web browser. Unlike Webleste, I led the porting efforts."
10 | // [
11 | // {
12 | // name: "GitHub",
13 | // url: "https://github.com/MercuryWorkshop/webshot",
14 | // icon: "code",
15 | // },
16 | // {
17 | // name: "Demo",
18 | // url: "https://youtube.com/watch?v=dQw4w9WgXcQ",
19 | // icon: "stadia_controller",
20 | // },
21 | // ],
22 | // ),
23 | new ProjectCardDetails(
24 | undefined,
25 | "MergeFlow",
26 | "Gemini-powered Git merge conflict resolution",
27 | 2025,
28 | "In 2025, me and a small team created MergeFlow, a smart Git merge conflict resolution tool powered by Gemini. It uses advanced AI algorithms to automatically resolve merge conflicts, making the process faster and more efficient. This was created for Hack Canada 2025.",
29 | [
30 | {
31 | name: "GitHub",
32 | url: "https://github.com/BomberFish/MergeFlow",
33 | icon: "code",
34 | },
35 | {
36 | name: "Demo Video",
37 | url: "https://www.youtube.com/watch?v=EkSgNgF8pcU",
38 | icon: "play_circle",
39 | },
40 | ],
41 | ),
42 | new ProjectCardDetails(
43 | undefined,
44 | "Voltaire",
45 | "Snazzy local LLM inference app for iOS",
46 | 2025,
47 | "Voltaire runs popular LLMs, including DeepSeek R1, LLaMa 3, and others, locally on iOS devices.",
48 | [
49 | {
50 | name: "GitHub",
51 | url: "https://github.com/BomberFish/Voltaire",
52 | icon: "code",
53 | },
54 | {
55 | name: "Demo Video",
56 | url: "https://youtube.com/watch?v=MipHd-EP9ok",
57 | icon: "play_circle",
58 | },
59 | ],
60 | ),
61 | new ProjectCardDetails(
62 | undefined,
63 | "fez-wasm",
64 | "Port of Fez (2012) to WebAssembly",
65 | 2025,
66 | "fez-wasm is a WebAssembly port of Fez, a puzzle-platformer first released in 2012. It is a heavy work in progress, with many portions non-functional.",
67 | [
68 | {
69 | name: "GitHub",
70 | url: "https://github.com/BomberFish/fez-wasm",
71 | icon: "code",
72 | },
73 | {
74 | name: "Demo",
75 | url: "https://fez.bomberfish.ca",
76 | icon: "stadia_controller",
77 | },
78 | ],
79 | ),
80 | new ProjectCardDetails(
81 | "/proj-thumbnails/Twitter Banner.png",
82 | "QuickSign",
83 | "iOS Codesigning App",
84 | 2025,
85 | "In late 2024 I joined the development of QuickSign, an app to sign sideloaded iOS apps. A private beta program is slated to begin in May 2025, with a full public release in July.",
86 | [
87 | {
88 | name: "Website",
89 | url: "https://quicksignteam.github.io",
90 | },
91 | {
92 | name: "Official Twitter",
93 | url: "https://twitter.com/QuickSigniOS",
94 | icon: "alternate_email",
95 | },
96 | ],
97 | ),
98 | new ProjectCardDetails(
99 | "/proj-thumbnails/celeste.webp",
100 | "Webleste",
101 | "Port of Celeste (2018) to WebAssembly",
102 | 2024,
103 | "Webleste (formerly celeste-wasm) is a port of the popular platformer game Celeste to WebAssembly. I helped out with it during its initial development in May 2024, and with the development of version 2.0 in April 2025. It is a complete port of the game, using experimental WASM support in .NET and the FNA game engine. I worked with my fellow colleagues at Mercury Workshop to help with porting the game.",
104 | [
105 | {
106 | name: "Play",
107 | url: "https://celeste.r58playz.dev",
108 | icon: "stadia_controller",
109 | },
110 | {
111 | name: "Writeup",
112 | url: "https://velzie.rip/blog/celeste-wasm",
113 | icon: "article",
114 | },
115 | {
116 | name: "GitHub",
117 | url: "https://github.com/MercuryWorkshop/celeste-wasm",
118 | icon: "code",
119 | },
120 | ],
121 | true,
122 | 2,
123 | ),
124 | new ProjectCardDetails(
125 | "/proj-thumbnails/anura.webp",
126 | "AnuraOS",
127 | "Contributor to webOS since v2.x",
128 | 2024,
129 | "AnuraOS is the next-gen webOS and development environment with full Linux emulation. That is to say, a full desktop environment running locally in your browser, with x86 Linux emulation. I've been making various contributions since March 2024, most of which reworked various parts of the UI. AnuraOS 2.0, which contains my contributions, was released in November 2024.",
130 | [
131 | {
132 | name: "Use Anura",
133 | url: "https://anura.pro",
134 | },
135 | ],
136 | true,
137 | 3,
138 | ),
139 | new ProjectCardDetails(
140 | "/proj-thumbnails/mandelapro.webp",
141 | "Mandela Pro",
142 | "Cancelled customization app",
143 | 2024,
144 | "Mandela Pro was a cancelled iOS customization app I created solo in early 2024. It was intended for iOS 16.0-17.0, but was cancelled due to the release of Dopamine 2.0 for 16.x versions and the lack of interest for iOS 17.0.",
145 | [],
146 | ),
147 | new ProjectCardDetails(
148 | "/proj-thumbnails/SSC2024_Social_Static_16x9.jpg",
149 | "Swift Student Challenge",
150 | "2024 Competition Winner",
151 | 2024,
152 | "In early 2024, I won the Swift Student Challenge, a programming competition run by Apple. My winning submission was a carbon footprint calculator.",
153 | [],
154 | true,
155 | 1,
156 | ),
157 | new ProjectCardDetails(
158 | "/proj-thumbnails/dssos.webp",
159 | "dssOS",
160 | "Live dev environment for ChromeOS devices",
161 | 2023,
162 | "dssOS was one of my first projects involving ChromeOS, and was a live development environment for ChromeOS devices. It used a modified diagnostic tool to boot into a Linux chroot, which you could use for programming. dssOS was created in November 2023.",
163 | [
164 | {
165 | name: "Website",
166 | url: "https://bomberfish.ca/dssOS/"
167 | },
168 | ],
169 | ),
170 | new ProjectCardDetails(
171 | "/proj-thumbnails/picasso.webp",
172 | "Picasso",
173 | "iOS customization app with 100k+ peak MAU",
174 | 2023,
175 | "Picasso was a customization app for iOS 15.0-17.0, taking advantage of various security vulnerabilities to allow for deep customization. At its peak, it had over 100,000 active users. I worked with sourcelocation to develop it, and it was first released in August 2023 on our own third-party marketplace separate from Apple's App Store.",
176 | [
177 | {
178 | name: "Source Release",
179 | url: "https://github.com/sourcelocation/Picasso-v3",
180 | icon: "code",
181 | },
182 | {
183 | name: "Discord",
184 | url: "https://discord.gg/b6bwaDK2VZ",
185 | icon: "chat",
186 | },
187 | ],
188 | true,
189 | 0,
190 | ),
191 | new ProjectCardDetails(
192 | "/proj-thumbnails/appcommander.webp",
193 | "AppCommander",
194 | "App Manager for iOS 15.0-18.4",
195 | 2023,
196 | "AppCommander (v1.x) was an app manager for iOS 15.0-16.1.2, and allowed the user to perform advanced app management using a sandbox escape that utilized the MacDirtyCow vunerability. Some key features included creating app backups, exporting IPA files, clearing app caches, and more. AppCommander 1.0.0 was released in July 2023.",
197 | [
198 | {
199 | name: "Source Code (v1)",
200 | url: "https://github.com/BomberFish/AppCommander-legacy",
201 | icon: "code",
202 | },
203 | {
204 | name: "Source Code (v2)",
205 | url: "https://github.com/BomberFish/AppCommander",
206 | icon: "code",
207 | },
208 | ],
209 | ),
210 | new ProjectCardDetails(
211 | "/proj-thumbnails/cowabunga.webp",
212 | "Cowabunga MDC",
213 | "Major contributor to customization app",
214 | 2023,
215 | "Cowabunga was a major project I contributed to in 2023. It was a customization app for iOS 14.0-16.1.2, using the MacDirtyCow vunerability to allow for deep customization. My contributions included adding tools such as an enterprise certificate blacklist remover, and a tool to remove the three-app limit on developer-signed apps.",
216 | [
217 | {
218 | name: "Source Code",
219 | url: "https://github.com/leminlimez/Cowabunga",
220 | icon: "code",
221 | },
222 | {
223 | name: "Website",
224 | url: "https://cowabun.ga",
225 | },
226 | {
227 | name: "Discord",
228 | url: "https://discord.gg/cowabunga",
229 | icon: "chat",
230 | },
231 | ],
232 | ),
233 | ];
234 |
--------------------------------------------------------------------------------
/src/SiteContent.tsx:
--------------------------------------------------------------------------------
1 | import "dreamland";
2 | import { articleCSS } from "./CommonCSS";
3 |
4 | export const FullArticle: Component<{}, {}> = function () {
5 | return (
6 |
7 |
8 |
9 |
10 |
11 |
12 | );
13 | };
14 |
15 | export const Intro: Component<{}, {}> = function () {
16 | this.css = `
17 | #kawaii {
18 | width: max(20rem, 30%);
19 | height: auto;
20 | margin: 0 0 1rem 2rem;
21 | }
22 |
23 | .intro {
24 | display: flex;
25 | flex-direction: row;
26 | align-items: center;
27 | justify-content: space-between;
28 |
29 | }
30 |
31 | @media (orientation: portrait), (max-width: 800px) {
32 | #kawaii {
33 | display: none; /* TODO: Figure something out */
34 | }
35 | }
36 | `;
37 |
38 | return (
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 | );
51 | };
52 |
53 | export const IntroSmall: Component<{}, {}> = function () {
54 | this.css = `
55 | h1 {
56 | font-size: 4rem!important;
57 | cursor: default;
58 | font-weight: bold!important;
59 | }
60 |
61 | // h1>span {
62 | // font-weight: 900!important;
63 | // transition: font-weight 0.25s ease,
64 | // letter-spacing 0.25s ease;
65 | // letter-spacing: 0em;
66 | // }
67 |
68 | // h1:hover > span {
69 | // font-weight: 100!important;
70 | // transition: font-weight 0.25s ease,
71 | // letter-spacing 0.25s ease;
72 | // letter-spacing: 0.09em;
73 | // }
74 | `;
75 | return (
76 |
77 |
78 | hiya! 👋
79 |
80 | i'm hariz, a 16 y/o high school student from canada :3
81 |
82 | i sometimes make use(ful|less)
projects among other stuff.
83 |
84 |
85 |
86 | as for .* engineering
, I'm interested in:
87 |
88 | embedded systems and hardware
89 | ios development with swiftui
90 |
91 | webdev (as you can tell from this immaculately put-together
92 | portfolio)
93 |
94 | ...and a little bit of security research!
95 |
96 |
97 |
98 | );
99 | };
100 |
101 | export const About: Component<{}, {}> = function () {
102 | return (
103 |
104 | i'm also...
105 |
106 | one of the winners of the 2024 swift student challenge
107 |
108 | fluent in the following programming languages:
109 |
110 | swift (the GOAT)
111 | javascript/typescript
112 | c/c++/objective-c
113 | bash
114 | python
115 |
116 |
117 |
118 | part of{" "}
119 |
120 | mercury workshop
121 |
122 | , a software development team best known for the{" "}
123 |
124 | sh1mmer
125 | {" "}
126 | chromebook exploit.
127 |
128 | an amateur music producer! stay tuned for more info!
129 |
130 |
131 | );
132 | };
133 |
134 | export const Contact: Component<{}, {}> = function () {
135 | return (
136 |
137 | get in touch!
138 |
139 |
140 |
141 | github
142 |
143 |
144 |
145 |
146 | fediverse
147 |
148 | (@fish@wetdry.world)
149 |
150 |
151 | if you use bluesky, you can follow
152 |
156 | @fish.wetdry.world.ap.brid.gy
157 |
158 | to view my posts on the fediverse. please note, this is
159 | usually a few minutes behind!
160 |
161 |
162 | if you use neither of those, you can view my latest post in the
163 | "yapping" tab above.
164 |
165 |
166 |
167 |
168 | email (hariz@bomberfish.ca)
169 |
170 |
171 | i might be slow to respond, since i don't check my email often.
172 |
173 | every email address @bomberfish.ca belongs to me.
174 |
175 |
176 |
177 | discord
178 |
179 |
180 | @bomberfish (main account)
181 |
182 | @realtimsweeneyepic
183 | @pageprotectionlayer
184 | @securepagetablemonitor
185 |
186 |
187 | {/* */}
188 | {/* no elon i am not calling it "X" */}
189 | {/*
190 | Twitter (inactive)
191 |
192 | */}
193 |
194 |
199 | matrix
200 | {" "}
201 | (@bomberfish:omada.cafe)
202 |
203 |
204 | signal: @bomberfish.77
205 |
206 | please only use this if all else fails!
207 |
208 |
209 |
210 |
211 | );
212 | };
213 |
214 | export const SiteMap: Component<{}, {}> = function () {
215 | return (
216 |
217 | other things on this site
218 |
229 |
230 | );
231 | };
232 |
233 | export const DesignPhilosophy: Component<{}, {}> = function () {
234 | return (
235 |
236 | website design philosophy
237 |
238 | be as keyboard-accessible as possible.
239 |
240 | javascript is not the enemy. take advantage of all the latest gizmos.
241 |
242 | always include source maps. why not show off your code?
243 |
244 |
245 |
246 | optimize for size. some people use (and pay for) Canadian cellular
247 | data.
248 |
249 | have some fun! Don't be too bland.
250 |
251 |
252 | );
253 | };
254 |
--------------------------------------------------------------------------------
/src/Status.ts:
--------------------------------------------------------------------------------
1 | // 100% generated by gpt-4o
2 |
3 | export class Emoji {
4 | shortcode: string;
5 | url: string;
6 | static_url: string;
7 | visible_in_picker: boolean;
8 |
9 | constructor(shortcode: string, url: string, static_url: string, visible_in_picker: boolean) {
10 | this.shortcode = shortcode;
11 | this.url = url;
12 | this.static_url = static_url;
13 | this.visible_in_picker = visible_in_picker;
14 | }
15 | }
16 |
17 | export class Mention {
18 | id: string;
19 | username: string;
20 | url: string;
21 | acct: string;
22 |
23 | constructor(id: string, username: string, url: string, acct: string) {
24 | this.id = id;
25 | this.username = username;
26 | this.url = url;
27 | this.acct = acct;
28 | }
29 | }
30 |
31 | export class Application {
32 | name: string;
33 | website: string | null;
34 |
35 | constructor(name: string, website: string | null) {
36 | this.name = name;
37 | this.website = website;
38 | }
39 | }
40 |
41 | export class Account {
42 | id: string;
43 | username: string;
44 | acct: string;
45 | display_name: string;
46 | locked: boolean;
47 | bot: boolean;
48 | discoverable: boolean | null;
49 | indexable: boolean;
50 | group: boolean;
51 | created_at: string;
52 | note: string;
53 | url: string;
54 | uri: string;
55 | avatar: string;
56 | avatar_static: string;
57 | header: string;
58 | header_static: string;
59 | followers_count: number;
60 | following_count: number;
61 | statuses_count: number;
62 | last_status_at: string;
63 | hide_collections: boolean | null;
64 | noindex: boolean;
65 | emojis: Emoji[];
66 | roles: string[];
67 | fields: any[];
68 |
69 | constructor(
70 | id: string, username: string, acct: string, display_name: string, locked: boolean, bot: boolean, discoverable: boolean | null,
71 | indexable: boolean, group: boolean, created_at: string, note: string, url: string, uri: string, avatar: string, avatar_static: string,
72 | header: string, header_static: string, followers_count: number, following_count: number, statuses_count: number, last_status_at: string,
73 | hide_collections: boolean | null, noindex: boolean, emojis: Emoji[], roles: string[], fields: any[]
74 | ) {
75 | this.id = id;
76 | this.username = username;
77 | this.acct = acct;
78 | this.display_name = display_name;
79 | this.locked = locked;
80 | this.bot = bot;
81 | this.discoverable = discoverable;
82 | this.indexable = indexable;
83 | this.group = group;
84 | this.created_at = created_at;
85 | this.note = note;
86 | this.url = url;
87 | this.uri = uri;
88 | this.avatar = avatar;
89 | this.avatar_static = avatar_static;
90 | this.header = header;
91 | this.header_static = header_static;
92 | this.followers_count = followers_count;
93 | this.following_count = following_count;
94 | this.statuses_count = statuses_count;
95 | this.last_status_at = last_status_at;
96 | this.hide_collections = hide_collections;
97 | this.noindex = noindex;
98 | this.emojis = emojis;
99 | this.roles = roles;
100 | this.fields = fields;
101 | }
102 | }
103 |
104 | export class Status {
105 | id: string;
106 | created_at: string;
107 | in_reply_to_id: string | null;
108 | in_reply_to_account_id: string | null;
109 | sensitive: boolean;
110 | spoiler_text: string;
111 | visibility: string;
112 | language: string;
113 | uri: string;
114 | url: string;
115 | replies_count: number;
116 | reblogs_count: number;
117 | favourites_count: number;
118 | edited_at: string | null;
119 | conversation_id: number;
120 | favourited: boolean;
121 | reblogged: boolean;
122 | muted: boolean;
123 | bookmarked: boolean;
124 | pinned: boolean;
125 | local_only: boolean;
126 | content: string;
127 | filtered: any[];
128 | reblog: any;
129 | application: Application;
130 | account: Account;
131 | media_attachments: any[];
132 | mentions: Mention[];
133 | tags: any[];
134 | emojis: Emoji[];
135 | reactions: any[];
136 | card: any;
137 | poll: any;
138 |
139 | constructor(
140 | id: string, created_at: string, in_reply_to_id: string | null, in_reply_to_account_id: string | null, sensitive: boolean, spoiler_text: string,
141 | visibility: string, language: string, uri: string, url: string, replies_count: number, reblogs_count: number, favourites_count: number,
142 | edited_at: string | null, conversation_id: number, favourited: boolean, reblogged: boolean, muted: boolean, bookmarked: boolean, pinned: boolean,
143 | local_only: boolean, content: string, filtered: any[], reblog: any, application: Application, account: Account, media_attachments: any[],
144 | mentions: Mention[], tags: any[], emojis: Emoji[], reactions: any[], card: any, poll: any
145 | ) {
146 | this.id = id;
147 | this.created_at = created_at;
148 | this.in_reply_to_id = in_reply_to_id;
149 | this.in_reply_to_account_id = in_reply_to_account_id;
150 | this.sensitive = sensitive;
151 | this.spoiler_text = spoiler_text;
152 | this.visibility = visibility;
153 | this.language = language;
154 | this.uri = uri;
155 | this.url = url;
156 | this.replies_count = replies_count;
157 | this.reblogs_count = reblogs_count;
158 | this.favourites_count = favourites_count;
159 | this.edited_at = edited_at;
160 | this.conversation_id = conversation_id;
161 | this.favourited = favourited;
162 | this.reblogged = reblogged;
163 | this.muted = muted;
164 | this.bookmarked = bookmarked;
165 | this.pinned = pinned;
166 | this.local_only = local_only;
167 | this.content = content;
168 | this.filtered = filtered;
169 | this.reblog = reblog;
170 | this.application = application;
171 | this.account = account;
172 | this.media_attachments = media_attachments;
173 | this.mentions = mentions;
174 | this.tags = tags;
175 | this.emojis = emojis;
176 | this.reactions = reactions;
177 | this.card = card;
178 | this.poll = poll;
179 | }
180 | }
181 |
--------------------------------------------------------------------------------
/src/Themes.tsx:
--------------------------------------------------------------------------------
1 | import "dreamland";
2 | import { store } from "./App";
3 |
4 | export const oled = {
5 | name: "OLED",
6 | shortName: "OLED",
7 | text: "#fbf9fb",
8 | overlay1: "#6e6b6e",
9 | surface2: "#413f41",
10 | surface0: "#1d1a1c",
11 | subtext0: "#a6a4a6",
12 | base: "#110f11",
13 | mantle: "#0b0a0b",
14 | crust: "#000000",
15 | accent: "#eba6ff",
16 | }
17 |
18 | export const mocha = {
19 | name: "Catppuccin Mocha",
20 | shortName: "Mocha",
21 | text: "#cdd6f4",
22 | overlay1: "#7f849c",
23 | surface2: "#585b70",
24 | surface0: "#313244",
25 | subtext0: "#a6adc8",
26 | base: "#1e1e2e",
27 | mantle: "#181825",
28 | crust: "#11111b",
29 | accent: "#cba6f7",
30 | };
31 |
32 |
33 | export const macchiato = {
34 | name: "Catppuccin Macchiato",
35 | shortName: "Macchiato",
36 | text: "#cad3f5",
37 | overlay1: "#8087a2",
38 | surface2: "#5b6078",
39 | surface0: "#363a4f",
40 | subtext0: "#a5adcb",
41 | base: "#24273a",
42 | mantle: "#1e2030",
43 | crust: "#181926",
44 | accent: "#c6a0f6",
45 | };
46 |
47 |
48 | export const frappe = {
49 | name: "Catppuccin Frappé",
50 | shortName: "Frappe",
51 | text: "#c6d0f5",
52 | overlay1: "#838ba7",
53 | surface2: "#626880",
54 | surface0: "#414559",
55 | subtext0: "#a5adce",
56 | base: "#303446",
57 | mantle: "#292c3c",
58 | crust: "#232634",
59 | accent: "#ca9ee6",
60 | };
61 |
62 |
63 | export const latte = {
64 | name: "Catppuccin Latte",
65 | shortName: "Latte",
66 | text: "#4c4f69",
67 | overlay1: "#8c8fa1",
68 | surface2: "#acb0be",
69 | surface0: "#ccd0da",
70 | subtext0: "#6c6f85",
71 | base: "#eff1f5",
72 | mantle: "#e6e9ef",
73 | crust: "#dce0e8",
74 | accent: "#8839ef",
75 | };
76 |
77 | export function updatePage() {
78 | var root = document.documentElement;
79 | console.debug(store.theme);
80 | if (
81 | store.theme.name == undefined ||
82 | store.theme.shortName == undefined ||
83 | store.theme.text == undefined ||
84 | store.theme.overlay1 == undefined ||
85 | store.theme.surface2 == undefined ||
86 | store.theme.surface0 == undefined ||
87 | store.theme.subtext0 == undefined ||
88 | store.theme.base == undefined ||
89 | store.theme.crust == undefined ||
90 | store.theme.accent == undefined
91 | ) {
92 | console.warn("theme is corrupted or out of date, resetting");
93 | store.theme = oled;
94 | updatePage();
95 | }
96 |
97 | document.head
98 | .querySelector("meta[name=theme-color]")!
99 | .setAttribute("content", store.theme.base);
100 | root.style.setProperty("--text", store.theme.text);
101 | root.style.setProperty("--overlay1", store.theme.overlay1);
102 | root.style.setProperty("--surface2", store.theme.surface2);
103 | root.style.setProperty("--surface0", store.theme.surface0);
104 | root.style.setProperty("--subtext0", store.theme.subtext0);
105 | root.style.setProperty("--base", store.theme.base);
106 | root.style.setProperty("--mantle", store.theme.mantle);
107 | root.style.setProperty("--crust", store.theme.crust);
108 | root.style.setProperty("--accent", store.theme.accent);
109 | document.body.classList.forEach((el) => {
110 | document.body.classList.remove(el);
111 | });
112 | document.body.classList.add(store.theme.shortName);
113 | }
114 |
115 | export const ThemePicker: Component<{}, {}> = function () {
116 |
117 | const themes = [oled, mocha, macchiato, frappe, latte];
118 |
119 | this.css = `
120 | background: transparent;
121 | border-radius: 0.4rem;
122 | border: none;
123 | color: var(--text);
124 | font-family: var(--font-body);
125 | font-size: 1rem;
126 | // padding: 0.75rem;
127 | cursor: pointer;
128 | // position: fixed;
129 | // bottom: 0;
130 | // right: 0;
131 | // z-index: 1000;
132 |
133 | display: flex;
134 | align-items: center;
135 |
136 | user-select: none;
137 | -webkit-user-drag: none;
138 | -webkit-user-select: none;
139 |
140 | .material-symbols-rounded {
141 | font-size: 1.5rem;
142 | }
143 |
144 | @media (orientation: portrait) {
145 | #theme-name {
146 | display: none;
147 | }
148 | }
149 | `;
150 |
151 | return (
152 | {
154 | e.preventDefault();
155 | let index = themes.indexOf(store.theme ?? oled);
156 | store.theme = themes[(index + 1) % themes.length];
157 |
158 | updatePage();
159 | }}
160 | title={use(store.theme.name)}
161 | // on:contextMenu={(e: PointerEvent) => {
162 | // e.preventDefault();
163 | // let index = themes.indexOf(store.theme);
164 | // store.theme = themes[(index - 1) % themes.length];
165 | // updatePage();
166 | // }}
167 | >
168 |
169 | {/* {use(store.theme.shortName)} */}
170 |
171 | );
172 | };
173 |
--------------------------------------------------------------------------------
/src/Utils.ts:
--------------------------------------------------------------------------------
1 | export function convertRemToPixels(rem: number) {
2 | return rem * parseFloat(getComputedStyle(document.documentElement).fontSize);
3 | }
4 |
--------------------------------------------------------------------------------
/src/vite-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ES2020",
4 | "useDefineForClassFields": true,
5 | "module": "ESNext",
6 | "lib": ["ES2020", "DOM", "DOM.Iterable"],
7 | "skipLibCheck": true,
8 |
9 | /* Bundler mode */
10 | "moduleResolution": "bundler",
11 | "allowImportingTsExtensions": true,
12 | "resolveJsonModule": true,
13 | "isolatedModules": true,
14 | "noEmit": true,
15 |
16 | /* Linting */
17 | "strict": true,
18 | "noUnusedLocals": true,
19 | "noUnusedParameters": true,
20 | "noFallthroughCasesInSwitch": true,
21 |
22 | "jsx": "react",
23 | "jsxFactory": "h",
24 | "jsxFragmentFactory": "Fragment",
25 | "types": ["dreamland"]
26 | },
27 | "include": ["src/**/*"],
28 | }
29 |
--------------------------------------------------------------------------------
/vite.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from "vite";
2 | import { dreamlandPlugin } from "vite-plugin-dreamland";
3 | import legacy from "@vitejs/plugin-legacy";
4 |
5 | export default defineConfig({
6 | plugins: [
7 | dreamlandPlugin(),
8 | legacy({
9 | targets: [
10 | "fully supports flexbox",
11 | "partially supports css-grid",
12 | "supports proxy",
13 | "not dead",
14 | "BlackBerry 10",
15 | "Firefox ESR",
16 | ],
17 | }),
18 | ],
19 | base: "",
20 | build: {
21 | sourcemap: true,
22 | cssMinify: "lightningcss",
23 | minify: "terser",
24 | },
25 | css: {
26 | devSourcemap: true,
27 | },
28 | server: {
29 | host: true,
30 | cors: false,
31 | },
32 | });
33 |
--------------------------------------------------------------------------------