diff --git a/.gitignore b/.gitignore index 1a35b77..54f682b 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ vendor/ # macOS .DS_Store +/_includes/notes_graph.json diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..50579a5 --- /dev/null +++ b/Gemfile @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +source "https://rubygems.org" + +git_source(:github) {|repo_name| "https://github.com/#{repo_name}" } + +gem "jekyll", "~> 4.4" +gem "jekyll-last-modified-at", git: "https://github.com/maximevaillancourt/jekyll-last-modified-at", branch: "add-support-for-files-in-git-submodules" +gem "webrick", "~> 1.9" +gem "nokogiri" diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..cf43fc6 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,226 @@ +GIT + remote: https://github.com/maximevaillancourt/jekyll-last-modified-at + revision: b7f1164861ba589660af3dc096dcbdff75d67145 + branch: add-support-for-files-in-git-submodules + specs: + jekyll-last-modified-at (1.3.2) + jekyll (>= 3.7, < 5.0) + +GEM + remote: https://rubygems.org/ + specs: + addressable (2.9.0) + public_suffix (>= 2.0.2, < 8.0) + base64 (0.3.0) + bigdecimal (4.1.2) + colorator (1.1.0) + concurrent-ruby (1.3.8) + csv (3.3.6) + em-websocket (0.5.3) + eventmachine (>= 0.12.9) + http_parser.rb (~> 0) + eventmachine (1.2.7) + ffi (1.17.4-aarch64-linux-gnu) + ffi (1.17.4-aarch64-linux-musl) + ffi (1.17.4-arm-linux-gnu) + ffi (1.17.4-arm-linux-musl) + ffi (1.17.4-arm64-darwin) + ffi (1.17.4-x86_64-darwin) + ffi (1.17.4-x86_64-linux-gnu) + ffi (1.17.4-x86_64-linux-musl) + forwardable-extended (2.6.0) + google-protobuf (4.35.1) + bigdecimal + rake (~> 13.3) + google-protobuf (4.35.1-aarch64-linux-gnu) + bigdecimal + rake (~> 13.3) + google-protobuf (4.35.1-aarch64-linux-musl) + bigdecimal + rake (~> 13.3) + google-protobuf (4.35.1-arm64-darwin) + bigdecimal + rake (~> 13.3) + google-protobuf (4.35.1-x86_64-darwin) + bigdecimal + rake (~> 13.3) + google-protobuf (4.35.1-x86_64-linux-gnu) + bigdecimal + rake (~> 13.3) + google-protobuf (4.35.1-x86_64-linux-musl) + bigdecimal + rake (~> 13.3) + http_parser.rb (0.8.1) + i18n (1.15.2) + concurrent-ruby (~> 1.0) + jekyll (4.4.1) + addressable (~> 2.4) + base64 (~> 0.2) + colorator (~> 1.0) + csv (~> 3.0) + em-websocket (~> 0.5) + i18n (~> 1.0) + jekyll-sass-converter (>= 2.0, < 4.0) + jekyll-watch (~> 2.0) + json (~> 2.6) + kramdown (~> 2.3, >= 2.3.1) + kramdown-parser-gfm (~> 1.0) + liquid (~> 4.0) + mercenary (~> 0.3, >= 0.3.6) + pathutil (~> 0.9) + rouge (>= 3.0, < 5.0) + safe_yaml (~> 1.0) + terminal-table (>= 1.8, < 4.0) + webrick (~> 1.7) + jekyll-sass-converter (3.1.0) + sass-embedded (~> 1.75) + jekyll-watch (2.2.1) + listen (~> 3.0) + json (2.21.2) + kramdown (2.5.2) + rexml (>= 3.4.4) + kramdown-parser-gfm (1.1.0) + kramdown (~> 2.0) + liquid (4.0.4) + listen (3.10.0) + logger + rb-fsevent (~> 0.10, >= 0.10.3) + rb-inotify (~> 0.9, >= 0.9.10) + logger (1.7.0) + mercenary (0.4.0) + nokogiri (1.19.4-aarch64-linux-gnu) + racc (~> 1.4) + nokogiri (1.19.4-aarch64-linux-musl) + racc (~> 1.4) + nokogiri (1.19.4-arm-linux-gnu) + racc (~> 1.4) + nokogiri (1.19.4-arm-linux-musl) + racc (~> 1.4) + nokogiri (1.19.4-arm64-darwin) + racc (~> 1.4) + nokogiri (1.19.4-x86_64-darwin) + racc (~> 1.4) + nokogiri (1.19.4-x86_64-linux-gnu) + racc (~> 1.4) + nokogiri (1.19.4-x86_64-linux-musl) + racc (~> 1.4) + pathutil (0.16.2) + forwardable-extended (~> 2.6) + public_suffix (7.0.5) + racc (1.8.1) + rake (13.4.2) + rb-fsevent (0.11.2) + rb-inotify (0.11.1) + ffi (~> 1.0) + rexml (3.4.4) + rouge (4.7.0) + safe_yaml (1.0.5) + sass-embedded (1.102.0-aarch64-linux-gnu) + google-protobuf (~> 4.31) + sass-embedded (1.102.0-aarch64-linux-musl) + google-protobuf (~> 4.31) + sass-embedded (1.102.0-arm-linux-gnueabihf) + google-protobuf (~> 4.31) + sass-embedded (1.102.0-arm-linux-musleabihf) + google-protobuf (~> 4.31) + sass-embedded (1.102.0-arm64-darwin) + google-protobuf (~> 4.31) + sass-embedded (1.102.0-x86_64-darwin) + google-protobuf (~> 4.31) + sass-embedded (1.102.0-x86_64-linux-gnu) + google-protobuf (~> 4.31) + sass-embedded (1.102.0-x86_64-linux-musl) + google-protobuf (~> 4.31) + terminal-table (3.0.2) + unicode-display_width (>= 1.1.1, < 3) + unicode-display_width (2.6.0) + webrick (1.9.2) + +PLATFORMS + aarch64-linux-gnu + aarch64-linux-musl + arm-linux-gnu + arm-linux-gnueabihf + arm-linux-musl + arm-linux-musleabihf + arm64-darwin + x86_64-darwin + x86_64-linux-gnu + x86_64-linux-musl + +DEPENDENCIES + jekyll (~> 4.4) + jekyll-last-modified-at! + nokogiri + webrick (~> 1.9) + +CHECKSUMS + addressable (2.9.0) sha256=7fdf6ac3660f7f4e867a0838be3f6cf722ace541dd97767fa42bc6cfa980c7af + base64 (0.3.0) sha256=27337aeabad6ffae05c265c450490628ef3ebd4b67be58257393227588f5a97b + bigdecimal (4.1.2) sha256=53d217666027eab4280346fba98e7d5b66baaae1b9c3c1c0ffe89d48188a3fbd + bundler (4.0.13) sha256=19f08be7f27022cf0b89f27da0b044ae075e8270a9ef44ad248a932614e1ca3b + colorator (1.1.0) sha256=e2f85daf57af47d740db2a32191d1bdfb0f6503a0dfbc8327d0c9154d5ddfc38 + concurrent-ruby (1.3.8) sha256=b2f1be836e968ccc78ccfce277ea79c72a88633f22306782c16ff23fb415d1e1 + csv (3.3.6) sha256=aba61e7e507a66f03d45cb1f3c4b6359861c3504038b422962875dce099e4456 + em-websocket (0.5.3) sha256=f56a92bde4e6cb879256d58ee31f124181f68f8887bd14d53d5d9a292758c6a8 + eventmachine (1.2.7) sha256=994016e42aa041477ba9cff45cbe50de2047f25dd418eba003e84f0d16560972 + ffi (1.17.4-aarch64-linux-gnu) sha256=b208f06f91ffd8f5e1193da3cae3d2ccfc27fc36fba577baf698d26d91c080df + ffi (1.17.4-aarch64-linux-musl) sha256=9286b7a615f2676245283aef0a0a3b475ae3aae2bb5448baace630bb77b91f39 + ffi (1.17.4-arm-linux-gnu) sha256=d6dbddf7cb77bf955411af5f187a65b8cd378cb003c15c05697f5feee1cb1564 + ffi (1.17.4-arm-linux-musl) sha256=9d4838ded0465bef6e2426935f6bcc93134b6616785a84ffd2a3d82bc3cf6f95 + ffi (1.17.4-arm64-darwin) sha256=19071aaf1419251b0a46852abf960e77330a3b334d13a4ab51d58b31a937001b + ffi (1.17.4-x86_64-darwin) sha256=aa70390523cf3235096cf64962b709b4cfbd5c082a2cb2ae714eb0fe2ccda496 + ffi (1.17.4-x86_64-linux-gnu) sha256=9d3db14c2eae074b382fa9c083fe95aec6e0a1451da249eab096c34002bc752d + ffi (1.17.4-x86_64-linux-musl) sha256=3fdf9888483de005f8ef8d1cf2d3b20d86626af206cbf780f6a6a12439a9c49e + forwardable-extended (2.6.0) sha256=1bec948c469bbddfadeb3bd90eb8c85f6e627a412a3e852acfd7eaedbac3ec97 + google-protobuf (4.35.1) sha256=a3a6471331d918f58dfa4d014a8f6286f0af2cf4840216bde52fcf2ea3fe3726 + google-protobuf (4.35.1-aarch64-linux-gnu) sha256=50ca44d0eeff3f8475e630a1accdd974256f3510694d574e2c9d6119ea8bc9e1 + google-protobuf (4.35.1-aarch64-linux-musl) sha256=d5c65cef6bd6498a9e5ed5f88cf6cf7e341c10b0a005e32137d5d1a2b6e8c18a + google-protobuf (4.35.1-arm64-darwin) sha256=d9c957df04fa89c749fa9a72a7b383eb4296efc9b2303dc6fd6fbe39c698ad6b + google-protobuf (4.35.1-x86_64-darwin) sha256=66b62b4df00931018a692806df66393efa960d6d2b7da69735187249f950d3ee + google-protobuf (4.35.1-x86_64-linux-gnu) sha256=c786439087512a3fbd199e9897d265b855f951d4027e218ea55e858d45969edd + google-protobuf (4.35.1-x86_64-linux-musl) sha256=91890eb0002934a339fdb7d77a147c46b7474b6799db27872b747b905837f744 + http_parser.rb (0.8.1) sha256=9ae8df145b39aa5398b2f90090d651c67bd8e2ebfe4507c966579f641e11097a + i18n (1.15.2) sha256=00f9eb62412fe593b2a65a97daa75300d37abb8f7202ec748e94b6d46a9dd1b5 + jekyll (4.4.1) sha256=4c1144d857a5b2b80d45b8cf5138289579a9f8136aadfa6dd684b31fe2bc18c1 + jekyll-last-modified-at (1.3.2) + jekyll-sass-converter (3.1.0) sha256=83925d84f1d134410c11d0c6643b0093e82e3a3cf127e90757a85294a3862443 + jekyll-watch (2.2.1) sha256=bc44ed43f5e0a552836245a54dbff3ea7421ecc2856707e8a1ee203a8387a7e1 + json (2.21.2) sha256=1f1d3b7cf2b3ba1a69beca0bb6db13d5438b80bff3cd54cdaaa620b9b07c1c6a + kramdown (2.5.2) sha256=1ba542204c66b6f9111ff00dcc26075b95b220b07f2905d8261740c82f7f02fa + kramdown-parser-gfm (1.1.0) sha256=fb39745516427d2988543bf01fc4cf0ab1149476382393e0e9c48592f6581729 + liquid (4.0.4) sha256=4fcfebb1a045e47918388dbb7a0925e7c3893e58d2bd6c3b3c73ec17a2d8fdb3 + listen (3.10.0) sha256=c6e182db62143aeccc2e1960033bebe7445309c7272061979bb098d03760c9d2 + logger (1.7.0) sha256=196edec7cc44b66cfb40f9755ce11b392f21f7967696af15d274dde7edff0203 + mercenary (0.4.0) sha256=b25a1e4a59adca88665e08e24acf0af30da5b5d859f7d8f38fba52c28f405138 + nokogiri (1.19.4-aarch64-linux-gnu) sha256=1269fb644a6de405057a53dd5c762b1209b43ca7424f839454d3dbc677c31a8f + nokogiri (1.19.4-aarch64-linux-musl) sha256=35c65b9ce72b3bb03207bdbe7067915019dc18c1b9b59139684bd6690fdd01af + nokogiri (1.19.4-arm-linux-gnu) sha256=a301313e38bb065d68239e79734bcd6f56fb6efaacebde29e9abf2a4735340ca + nokogiri (1.19.4-arm-linux-musl) sha256=588923c101bcfa78869734d247d25b598674323e7f22474fc468f6e5647311eb + nokogiri (1.19.4-arm64-darwin) sha256=a46db9853286e6597b36ebc6953817d15acf3a299583eb3f89fdc6f91dd63527 + nokogiri (1.19.4-x86_64-darwin) sha256=7fd17057d3e1f00e9954a74b3cd76595d3d4a5ef233b7ed9599047c204f70551 + nokogiri (1.19.4-x86_64-linux-gnu) sha256=379fae440b28915e3f19d752ce2dcf8465ed2b2fbefd2a7ca0dd497bc981a06a + nokogiri (1.19.4-x86_64-linux-musl) sha256=17dfb7c1fa194ae02fbf7c51a7afc8d278045ab3fdacfd86f91d02d7b274470b + pathutil (0.16.2) sha256=e43b74365631cab4f6d5e4228f812927efc9cb2c71e62976edcb252ee948d589 + public_suffix (7.0.5) sha256=1a8bb08f1bbea19228d3bed6e5ed908d1cb4f7c2726d18bd9cadf60bc676f623 + racc (1.8.1) sha256=4a7f6929691dbec8b5209a0b373bc2614882b55fc5d2e447a21aaa691303d62f + rake (13.4.2) sha256=cb825b2bd5f1f8e91ca37bddb4b9aaf345551b4731da62949be002fa89283701 + rb-fsevent (0.11.2) sha256=43900b972e7301d6570f64b850a5aa67833ee7d87b458ee92805d56b7318aefe + rb-inotify (0.11.1) sha256=a0a700441239b0ff18eb65e3866236cd78613d6b9f78fea1f9ac47a85e47be6e + rexml (3.4.4) sha256=19e0a2c3425dfbf2d4fc1189747bdb2f849b6c5e74180401b15734bc97b5d142 + rouge (4.7.0) sha256=dba5896715c0325c362e895460a6d350803dbf6427454f49a47500f3193ea739 + safe_yaml (1.0.5) sha256=a6ac2d64b7eb027bdeeca1851fe7e7af0d668e133e8a88066a0c6f7087d9f848 + sass-embedded (1.102.0-aarch64-linux-gnu) sha256=087f377fa4135a8f67f5f422781b59815e99b8fd3aec335935c50a47c2a205fd + sass-embedded (1.102.0-aarch64-linux-musl) sha256=12bb4091972499241c35304ca11ca2c314764badf1b9933a8d437ba62432b538 + sass-embedded (1.102.0-arm-linux-gnueabihf) sha256=566b1188e4f923366f494a5d95e4e5e03864ae55bae5ea52beb2c30b1b9e2915 + sass-embedded (1.102.0-arm-linux-musleabihf) sha256=1ca396610bf4f4aa8f849b67a9f2720f67d9f3b42651072eafee786aece314cf + sass-embedded (1.102.0-arm64-darwin) sha256=8e18b2dd94b232c2dd73984c579f77bbc1a066028f4675c8989ac34fa40d14dc + sass-embedded (1.102.0-x86_64-darwin) sha256=3e78c6ac5be0ba4236d075bd044a49d0f515d54799f7d6f253c71d325ffedac0 + sass-embedded (1.102.0-x86_64-linux-gnu) sha256=9815b7604123a9a44a65d44d5e58e7af1c7005174b745cda83bad4c9e3760ab3 + sass-embedded (1.102.0-x86_64-linux-musl) sha256=9e3c15eb5d83784adf3b946d4fc5d8a32aed25566a2fee939f25dd1e1d217ddf + terminal-table (3.0.2) sha256=f951b6af5f3e00203fb290a669e0a85c5dd5b051b3b023392ccfd67ba5abae91 + unicode-display_width (2.6.0) sha256=12279874bba6d5e4d2728cef814b19197dbb10d7a7837a869bab65da943b7f5a + webrick (1.9.2) sha256=beb4a15fc474defed24a3bda4ffd88a490d517c9e4e6118c3edce59e45864131 + +BUNDLED WITH + 4.0.13 diff --git a/README.md b/README.md index f9a19d0..49d3189 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,16 @@ # brendan-ch.github.io This is my personal webpage built using Jekyll and GitHub Pages. + +It is based on the [digital-garden-jekyll-template](https://github.com/maximevaillancourt/digital-garden-jekyll-template) by Maxime +Vaillancourt. The MIT license of the project: + +``` +Copyright (c) 2020 Maxime Vaillancourt. + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +``` diff --git a/_config.yml b/_config.yml new file mode 100644 index 0000000..655501c --- /dev/null +++ b/_config.yml @@ -0,0 +1,20 @@ +exclude: [ '_includes/notes_graph.json' ] + +plugins: + - jekyll-last-modified-at + +open_external_links_in_new_tab: true +use_html_extension: false +permalink: pretty +relative_permalinks: false + +collections: + notes: + output: true + permalink: /:slug/ + +defaults: + - scope: + path: "_notes/**/*.md" + values: + layout: "note" diff --git a/_includes/navigation.html b/_includes/navigation.html index 2766bc7..c0288a5 100644 --- a/_includes/navigation.html +++ b/_includes/navigation.html @@ -1,20 +1,9 @@ diff --git a/_layouts/default.html b/_layouts/default.html index 1bdf0c1..e858e4f 100644 --- a/_layouts/default.html +++ b/_layouts/default.html @@ -4,14 +4,15 @@ - + - - - - - - + + + + + + @@ -19,16 +20,19 @@ {{ page.title }} -
- {% include navigation.html %} -
-
- {{ content }} -
- diff --git a/_layouts/note.html b/_layouts/note.html new file mode 100644 index 0000000..bc86381 --- /dev/null +++ b/_layouts/note.html @@ -0,0 +1,26 @@ +--- +layout: default +--- + +

{{ page.title }}

+ +{{ content }} + +
+ + + + + +
diff --git a/_layouts/page_moved.html b/_layouts/page_moved.html new file mode 100644 index 0000000..1690523 --- /dev/null +++ b/_layouts/page_moved.html @@ -0,0 +1,6 @@ +--- +layout: default +--- + +

Page moved

+

This page has been moved. {{ content }}

\ No newline at end of file diff --git a/_notes/cmes-mobile.md b/_notes/cmes-mobile.md new file mode 100644 index 0000000..1874554 --- /dev/null +++ b/_notes/cmes-mobile.md @@ -0,0 +1,26 @@ +--- +title: CMES Mobile App +--- + +![cmes-mobile-app.png](../assets/project/cmes-mobile-app.png "Screenshots of the CMES app, showing the My Library screen and a web view.") + +**App development project for volunteer organization Techies Without Borders.** +I helped implement the CMES mobile app, facilitating the download, viewing and +playback of medical education content in resource-constrained countries. + +In the early stages, I built the download screen and business logic, the PDF +viewer integration, and background audio playback using native code. Later, I +built the native web view to integrate with +the [CMES-Pi](https://cmesworld.org/cmes_product-Pi.html) solution, simplifying +the business logic while adding support for future edge platforms. + +The app's front-end uses Capacitor and Angular, with several Capacitor plugins +in Swift + Java to bundle native functionality. + +This app is actively used in medical facilities in Uganda and Nepal, to name a +few. + +- [App Store](https://apps.apple.com/us/app/cmes/id1276335909) +- [Google Play](https://play.google.com/store/apps/details?id=org.cmesworld.www.cmes_piandroid_app) +- [Techies Without Borders](https://techieswithoutborders.us/) +- [CMES Project](https://cmesworld.org/) diff --git a/projects/dont-wake-sandie/index.md b/_notes/dont-wake-sandie.md similarity index 89% rename from projects/dont-wake-sandie/index.md rename to _notes/dont-wake-sandie.md index bc9fa0d..31207cf 100644 --- a/projects/dont-wake-sandie/index.md +++ b/_notes/dont-wake-sandie.md @@ -1,6 +1,5 @@ --- title: Don't Wake Sandie -layout: project --- @@ -17,5 +16,5 @@ UI development, artwork integration, and version control. There were so many moving parts, and I really aimed to get as much input for the gameplay design as I could from the team. -[itch.io (play the game!)](https://bchendev.itch.io/dont-wake-sandie){: .primary-action } -{: .horizontal-wrapper } +[Play the game on itch.io!](https://bchendev.itch.io/dont-wake-sandie) + diff --git a/_notes/index.md b/_notes/index.md new file mode 100644 index 0000000..4cd6a28 --- /dev/null +++ b/_notes/index.md @@ -0,0 +1,24 @@ +--- +title: "Brendan Chen" +layout: default +isIndexPage: 1 +permalink: / +--- + +I'm Brendan, a recently graduated Software Engineering student who attended +Chapman University. I'm currently an associate software engineer at Cargill. I'm +also the creator of [OpenAppLock](https://github.com/brendan-ch/OpenAppLock), an +open-source time blocker for iOS, +and [Interchange](https://interchange.bchen.dev), a free shuttle app for Chapman +students. + +I believe that no matter which path an app's development takes, it should be +grounded in real experiences. + +Feel free to [say hi](mailto:brendan@bchen.dev)! + +- [[Projects]] +- [View my resume](/assets/resume.pdf) + +![Picture of me taken at the Senso-ji Buddhist Temple in Asakusa, Tokyo, Japan](../assets/me-1.png "Picture of me taken at the Senso-ji Buddhist Temple in Asakusa, Tokyo, Japan") + diff --git a/_notes/interchange.md b/_notes/interchange.md new file mode 100644 index 0000000..e475b91 --- /dev/null +++ b/_notes/interchange.md @@ -0,0 +1,15 @@ +--- +title: Interchange +--- + +![interchange-screenshots.png](../assets/project/interchange-screenshots.png "Screenshots of Interchange.") + +**An iOS app for college transit, currently available for Chapman University.** +View routes, shuttle locations, and estimated arrival times in a sleek, +easy-to-use interface. I built this app using SwiftUI, Node.js and Apollo +GraphQL, with Redis as a primary storage mechanism. + +- [Download on the App Store](https://apps.apple.com/us/app/interchange-college-commute/id6739968742) +- [Join the TestFlight](https://testflight.apple.com/join/HbuHfUgW) +- [Website](https://interchange.bchen.dev/) + diff --git a/_notes/power-to-the-people.md b/_notes/power-to-the-people.md new file mode 100644 index 0000000..3897b8e --- /dev/null +++ b/_notes/power-to-the-people.md @@ -0,0 +1,26 @@ +--- +title: Power to the People +--- + +![power-to-the-people.png](../assets/project/power-to-the-people.png "Screenshots of Power to the People, an iOS app designed to make traffic stops safer.") + +**An iPhone app designed to make traffic stops safer for marginalized +communities.** Record interactions with police, assign and text emergency +contacts, and be informed of your rights. I worked in a student team of 4, +including [David Sohn](https://www.linkedin.com/in/sohn-david/), [Jacob Zamore](https://www.linkedin.com/in/jacob-zamore/), +and [Patrick Smith](https://www.linkedin.com/in/patrick-smith-ld/), to prototype +and build a proof of concept in 36 hours. The app was selected for the * +*President's Pick award** at [CruzHacks 2024](https://cruzhacks.com/), the +premier hackathon of UC Santa Cruz. + +- [GitHub](https://github.com/brendan-ch/PowerToThePeople) +- [Devpost](https://devpost.com/software/power-to-the-people-lbhxyd) + +My contribution was the iOS app prototype, of which a demo is shown below. I +built the primary user flow of recording a police interaction, simultaneously +using the front and back iPhone cameras to capture all angles. Activating the +recording also displays the "Know Your Rights" screen, displaying basic dos and +don'ts. Finally, I built a way to view previous recordings and share the files +using the iOS share sheet. + + diff --git a/projects/index.md b/_notes/projects.md similarity index 53% rename from projects/index.md rename to _notes/projects.md index 24bd440..5ea4392 100644 --- a/projects/index.md +++ b/_notes/projects.md @@ -1,42 +1,44 @@ --- title: Projects -layout: default --- -# Projects - ## Games -- [Resonance](/projects/resonance) +- [[Resonance]] - **IEEE GameSig Finalist**, 2026 - A cyberpunk-themed game show shooter. -- [Don't Wake Sandie](/projects/dont-wake-sandie) +- [[Don't Wake Sandie]] - A game about not waking up a beloved hungover corgi ## Personal -- [Interchange](/projects/interchange) +- [[Interchange]] - An iOS app for college transit, now on the App Store! -- [Timestamp](/projects/timestamp) +- [[Timestamp]] - An unintrusive, open source Pomodoro timer for macOS. -- [Sourcebook](/projects/sourcebook) +- [[Sourcebook]] - A lightweight content management system (CMS) for class websites. ## Hackathons -- [teech.ai](/projects/teech-ai-cal-hacks-12) +- [[teech.ai]] - Cal Hacks 12.0 - - A tutoring app to make education more accessible, built with SwiftUI and Gemini Vision API. -- [Power to the People](/projects/power-to-the-people) + - A tutoring app to make education more accessible, built with SwiftUI and + Gemini Vision API. +- [[Power to the People]] - **President's Pick**, CruzHacks 2024 - - An iOS app designed to make traffic stops safer for marginalized communities. + - An iOS app designed to make traffic stops safer for marginalized + communities. ## Work -- [The Farmer's Dog Trivia Game](/projects/the-farmers-dog-trivia) - - A Windows kiosk application designed to connect customers with the Farmer's Dog experience. +- [[The Farmer's Dog Trivia Game]] + - A Windows kiosk application designed to connect customers with the + Farmer's Dog experience. ## Community -- [CMES Mobile App](/projects/cmes-mobile/) - - One of my earliest projects. A cross-platform mobile app to deliver educational medical content to end users, part of [Techies Without Borders](https://techieswithoutborders.us/). +- [[CMES Mobile App]] + - One of my earliest projects. A cross-platform mobile app to deliver + educational medical content to end users, part + of [Techies Without Borders](https://techieswithoutborders.us/). diff --git a/_notes/resonance.md b/_notes/resonance.md new file mode 100644 index 0000000..8f05b5e --- /dev/null +++ b/_notes/resonance.md @@ -0,0 +1,40 @@ +--- +title: Resonance +--- + +![resonance-screenshot.png](../assets/project/resonance-screenshot.png "Screenshot of Resonance") + +Resonance is a cyberpunk-themed game show shooter. Enter the arena, blast your +opponents, and become the star of the show. I worked with a student team of 12 +to create this game over multiple months. The game was selected as an **IEEE +GameSig finalist**. + +*Steam link coming soon!* + +My core role was to implement the game's networking logic using PurrNet, an +open-source library for Unity. + +My first project was to implement networking for **Arena**, a free-for-all PVP +game mode, where the player with the most eliminations wins. I learned how to +isolate game logic on the server and synchronize state on each client. The +networked API for Arena is used by every aspect of the game, including the +scoreboard UI and spotlight mechanic. Following a pivot in the game’s core +direction, I successfully handed this system to another engineer, who +implemented a rating system for style points. + +Another project was the **build system**. Having a server dependency and Steam +integration meant that the environment differed from development to production. +We found it painful to prepare a build for each class-mandated playtest. With +the help of Claude, I created a two-step system: an editor script to build and +configure dependencies in one step, and a nightly GitHub Actions pipeline. +Besides simplifying the build process, this created another positive side effect +by ensuring we fixed compiler issues proactively. + +I'm currently working on a client-side prediction model to match other FPS games +on the market. + +Even with our team size, the most important thing I learned was how to manage +scope and scale. Each one of us pushed ourselves to the limits of our knowledge, +going from bare theoretical understanding to practical working implementations. +The goal was never to get things right on the first try; it was to learn and +realize new ideas in multiple passes. diff --git a/projects/sourcebook/index.md b/_notes/sourcebook.md similarity index 69% rename from projects/sourcebook/index.md rename to _notes/sourcebook.md index 8f3d544..938438f 100644 --- a/projects/sourcebook/index.md +++ b/_notes/sourcebook.md @@ -1,9 +1,8 @@ --- title: Sourcebook -layout: project --- -![sourcebook.png](assets/sourcebook.png "Screenshot of Sourcebook, a lightweight CMS for class websites.") +![sourcebook.png](../assets/project/sourcebook.png "Screenshot of Sourcebook, a lightweight CMS for class websites.") **A lightweight content management system (CMS) designed to build class websites.** I designed it to be a self-hosted alternative for popular apps like @@ -13,5 +12,5 @@ I designed an entity-relationship diagram, MySQL database schema, and HTML/CSS high-fidelity prototype to support the project and show to professors. I then built a lightweight full-stack application using Python, Flask, and MySQL. -[GitHub](https://github.com/brendan-ch/sourcebook){: .primary-action } -{: .horizontal-wrapper } +[GitHub](https://github.com/brendan-ch/sourcebook) + diff --git a/_notes/tad-pool.md b/_notes/tad-pool.md new file mode 100644 index 0000000..22ee34a --- /dev/null +++ b/_notes/tad-pool.md @@ -0,0 +1,24 @@ +--- +title: Tad-Pool +--- + +![tad-pool.png](../assets/project/tad-pool.png "Screenshots of Tad-Pool, a carpooling app for college students.") + +**A mobile app designed to make carpooling easier for college students.** Find +carpools based on time and location, and get rewarded for helping to reduce CO2 +emissions. I worked +with [Jazmine Stanek](https://www.linkedin.com/in/vjazminestanek/) +and [Isabelle Woo](https://www.linkedin.com/in/isabellewoo/) to create the UI/UX +design using Figma and FigJam, in a period of 24 hours for +[FullyBeyond 2024](https://fullybeyond.acmcsuf.com/). + +The project reached the finalist judging stage. + +- [High-fidelity design](https://www.figma. + com/design/nTKCcwftKrg27wlP5mmy9e/Tad-Pool-Design?node-id=13-1837&node-type=canvas&t=YKuVvM6RAPs4hTIo-11) +- [Low-fidelity design](https://www.figma. + com/design/nTKCcwftKrg27wlP5mmy9e/Tad-Pool-Design?node-id=0-1&node-type=canvas&t=YKuVvM6RAPs4hTIo-11) +- [FigJam board](https://www.figma. + com/board/Dct7GuhKFYq8maw0KoAVBV/Product-Brainstorm-FullyBeyond?node-id=0-1&node-type=canvas&t=g7RKLLo5IoU84ndk-11) +- [Devpost](https://devpost.com/software/tad-pool) + diff --git a/_notes/teech-ai-cal-hacks-12.md b/_notes/teech-ai-cal-hacks-12.md new file mode 100644 index 0000000..b190ed7 --- /dev/null +++ b/_notes/teech-ai-cal-hacks-12.md @@ -0,0 +1,29 @@ +--- +title: teech.ai +--- + + + +**A proof-of-concept tutoring app for students learning math.** Using the phone +camera, the app sees and understands math problems, guiding students through +problems with hints and step-by-step questions. We added text-to-speech (TTS) to +give our app a voice, further engaging students and making it feel like a more +personal experience. + +[Tri Vu](https://www.linkedin.com/in/tri-q-vu/) built a web interface prototype +and Python-based backend utilizing the Gemini Vision API and Fish Audio for TTS. + +I built a native proof-of-concept using SwiftUI, AVFoundation, and other native +frameworks. In the app, I built a chat and camera interface, integrating with +Tri's backend by sending image and prompt data. Swiping to the right reveals the +user's chat history, which is also continuously synced with the backend. +Design-wise, I decided to use this gesture-based approach in order to bring the +camera interface front and center. + +The app was built in 48 hours for **Cal Hacks 12.0**, the world's largest +collegiate hackathon. + +- [GitHub](https://github.com/brendan-ch/teecher-ios) +- [Devpost](https://devpost.com/software/teech-ai) +- [Cal Hacks](https://www.calhacks.io) + diff --git a/projects/the-farmers-dog-trivia/index.md b/_notes/the-farmers-dog-trivia.md similarity index 71% rename from projects/the-farmers-dog-trivia/index.md rename to _notes/the-farmers-dog-trivia.md index e97dd66..e880eaa 100644 --- a/projects/the-farmers-dog-trivia/index.md +++ b/_notes/the-farmers-dog-trivia.md @@ -1,19 +1,18 @@ --- title: The Farmer's Dog Trivia Game -layout: project --- -![farmers-dog.png](assets/farmers-dog.png) +![farmers-dog.png](../assets/project/farmers-dog.png) **A Windows kiosk application designed to connect customers with the Farmer's Dog experience.** Play the interactive trivia game, score points, and win swag! I worked with [Walter Cheng](https://www.linkedin.com/in/walter-j-cheng/) to plan out dependencies and requirements, set up the codebase, and implement the -screens for the app using React Native for Windows. +screens for the app using React Native for Windows. "I’ve worked with Brendan for many years, and he is the first person I turn to for web/app development. He’s knowledgeable and efficient, and his task -management skills make him an ideal project member." — Walter Cheng, project overseer +management skills make him an ideal project member." — Walter Cheng, project +overseer -[The Farmer’s Dog](https://thefarmersdog.com/){: .primary-action } -{: .horizontal-wrapper } +[The Farmer’s Dog](https://thefarmersdog.com/) diff --git a/_notes/timestamp.md b/_notes/timestamp.md new file mode 100644 index 0000000..6bdb0f7 --- /dev/null +++ b/_notes/timestamp.md @@ -0,0 +1,11 @@ +--- +title: Timestamp +--- + +![Screenshot of the Timestamp app and the settings window.](../assets/project/timestamp-screenshot.png) + +A simple, unintrusive Pomodoro timer for macOS which lives in the menu bar. I +built it with SwiftUI and made it open source. + +[Download the app](https://github.com/brendan-ch/timestamp/releases) +[View the code](https://github.com/brendan-ch/timestamp) diff --git a/_plugins/bidirectional_links_generator.rb b/_plugins/bidirectional_links_generator.rb new file mode 100644 index 0000000..78184b5 --- /dev/null +++ b/_plugins/bidirectional_links_generator.rb @@ -0,0 +1,111 @@ +# frozen_string_literal: true +class BidirectionalLinksGenerator < Jekyll::Generator + def generate(site) + graph_nodes = [] + graph_edges = [] + + all_notes = site.collections['notes'].docs + all_pages = site.pages + + all_docs = all_notes + all_pages + + link_extension = !!site.config["use_html_extension"] ? '.html' : '' + + # Convert all Wiki/Roam-style double-bracket link syntax to plain HTML + # anchor tag elements () with "internal-link" CSS class + all_docs.each do |current_note| + all_docs.each do |note_potentially_linked_to| + note_title_regexp_pattern = Regexp.escape( + File.basename( + note_potentially_linked_to.basename, + File.extname(note_potentially_linked_to.basename) + ) + ).gsub('\_', '[ _]').gsub('\-', '[ -]').capitalize + + title_from_data = note_potentially_linked_to.data['title'] + if title_from_data + title_from_data = Regexp.escape(title_from_data) + end + + new_href = "#{site.baseurl}#{note_potentially_linked_to.url}#{link_extension}" + anchor_tag = "\\1" + + # Replace double-bracketed links with label using note title + # [[A note about cats|this is a link to the note about cats]] + current_note.content.gsub!( + /\[\[#{note_title_regexp_pattern}\|(.+?)(?=\])\]\]/i, + anchor_tag + ) + + # Replace double-bracketed links with label using note filename + # [[cats|this is a link to the note about cats]] + current_note.content.gsub!( + /\[\[#{title_from_data}\|(.+?)(?=\])\]\]/i, + anchor_tag + ) + + # Replace double-bracketed links using note title + # [[a note about cats]] + current_note.content.gsub!( + /\[\[(#{title_from_data})\]\]/i, + anchor_tag + ) + + # Replace double-bracketed links using note filename + # [[cats]] + current_note.content.gsub!( + /\[\[(#{note_title_regexp_pattern})\]\]/i, + anchor_tag + ) + end + + # At this point, all remaining double-bracket-wrapped words are + # pointing to non-existing pages, so let's turn them into disabled + # links by greying them out and changing the cursor + current_note.content = current_note.content.gsub( + /\[\[([^\]]+)\]\]/i, # match on the remaining double-bracket links + <<~HTML.delete("\n") # replace with this HTML (\\1 is what was inside the brackets) + + [[ + \\1 + ]] + HTML + ) + end + + # Identify note backlinks and add them to each note + all_notes.each do |current_note| + # Nodes: Jekyll + notes_linking_to_current_note = all_notes.filter do |e| + e.url != current_note.url && e.content.include?(current_note.url) + end + + # Nodes: Graph + graph_nodes << { + id: note_id_from_note(current_note), + path: "#{site.baseurl}#{current_note.url}#{link_extension}", + label: current_note.data['title'], + } unless current_note.path.include?('_notes/index.html') + + # Edges: Jekyll + current_note.data['backlinks'] = notes_linking_to_current_note + + # Edges: Graph + notes_linking_to_current_note.each do |n| + graph_edges << { + source: note_id_from_note(n), + target: note_id_from_note(current_note), + } + end + end + + File.write('_includes/notes_graph.json', JSON.dump({ + edges: graph_edges, + nodes: graph_nodes, + })) + end + + def note_id_from_note(note) + note.data['title'].bytes.join + end +end diff --git a/_plugins/empty_front_matter_note_injector.rb b/_plugins/empty_front_matter_note_injector.rb new file mode 100644 index 0000000..83fd4b2 --- /dev/null +++ b/_plugins/empty_front_matter_note_injector.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +EMPTY_FRONT_MATTER = <<~JEKYLL + --- + --- + +JEKYLL + +# Inject empty front matter in notes that don't have any +Jekyll::Hooks.register :site, :after_init do |site| + Dir.glob(site.collections['notes'].relative_directory + '/**/*.md').each do |filename| + raw_note_content = File.read(filename) + unless raw_note_content.start_with?('---') + raw_note_content.prepend(EMPTY_FRONT_MATTER) + File.write(filename, raw_note_content) + end + end +end diff --git a/_plugins/last_modified_at_generator.rb b/_plugins/last_modified_at_generator.rb new file mode 100644 index 0000000..ea9b1f4 --- /dev/null +++ b/_plugins/last_modified_at_generator.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +require 'fileutils' +require 'pathname' +require 'jekyll-last-modified-at' + +module Recents + # Generate change information for all markdown pages + class Generator < Jekyll::Generator + def generate(site) + items = site.collections['notes'].docs + items.each do |page| + timestamp = Jekyll::LastModifiedAt::Determinator.new(site.source, page.path, '%FT%T%:z').to_s + page.data['last_modified_at_timestamp'] = timestamp + end + end + end +end diff --git a/_plugins/markdown-highlighter.rb b/_plugins/markdown-highlighter.rb new file mode 100644 index 0000000..2ef933c --- /dev/null +++ b/_plugins/markdown-highlighter.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +# Turns ==something== in Markdown to something in output HTML + +Jekyll::Hooks.register [:notes], :pre_render do |doc| + replace(doc) +end + +Jekyll::Hooks.register [:pages], :pre_render do |doc| + # jekyll considers anything at the root as a page, + # we only want to consider actual pages + next unless doc.path.start_with?('_pages/') + replace(doc) +end + +def replace(doc) + doc.content.gsub!(/==+([^ ](.*?)?[^ .=])==+/, "\\1") +end diff --git a/_plugins/open_external_links_in_new_tab.rb b/_plugins/open_external_links_in_new_tab.rb new file mode 100644 index 0000000..8f966c5 --- /dev/null +++ b/_plugins/open_external_links_in_new_tab.rb @@ -0,0 +1,28 @@ +# If the configuration sets `open_external_links_in_new_tab` to a truthy value, +# add 'target=_blank' to anchor tags that don't have `internal-link` class + +# frozen_string_literal: true +require 'nokogiri' + +Jekyll::Hooks.register [:notes], :post_convert do |doc| + convert_links(doc) +end + +Jekyll::Hooks.register [:pages], :post_convert do |doc| + # jekyll considers anything at the root as a page, + # we only want to consider actual pages + next unless doc.path.start_with?('_pages/') + convert_links(doc) +end + +def convert_links(doc) + open_external_links_in_new_tab = !!doc.site.config["open_external_links_in_new_tab"] + + if open_external_links_in_new_tab + parsed_doc = Nokogiri::HTML::DocumentFragment.parse(doc.content) + parsed_doc.css("a:not(.internal-link):not(.footnote):not(.reversefootnote)").each do |link| + link.set_attribute('target', '_blank') + end + doc.content = parsed_doc.inner_html + end +end diff --git a/projects/assets/app-store-icon.svg b/assets/app-store-icon.svg similarity index 100% rename from projects/assets/app-store-icon.svg rename to assets/app-store-icon.svg diff --git a/assets/css/colors.css b/assets/css/colors.css index cb2e54b..f62c534 100644 --- a/assets/css/colors.css +++ b/assets/css/colors.css @@ -1,3 +1,18 @@ :root { - --background-color: #f4f4f4; + --color-background-1: #f4f4f4; + --color-background-2: #e4e4e4; + --color-primary-1: #000000; + --color-accent: #008891; + --color-accent-hover: #539397; } + +@media (prefers-color-scheme: dark) { + :root { + --color-background-1: #171616; + --color-background-2: #222222; + --color-primary-1: #eeeeee; + --color-accent: #00B7C3; + --color-accent-hover: #70c1c6; + } +} + diff --git a/assets/css/content.css b/assets/css/content.css deleted file mode 100644 index c189040..0000000 --- a/assets/css/content.css +++ /dev/null @@ -1,36 +0,0 @@ -/* Custom classes for styling elements on a page, such as links */ - -.horizontal-wrapper { - display: flex; - flex-direction: row; - gap: 8px; - align-items: flex-start; -} - -.primary-action { - background: black; - padding: 0.8em; - color: white; - text-decoration-line: unset; - border-radius: 4px; - border-style: solid; - border-width: 1px; - border-color: black; - box-sizing: border-box; -} - -.secondary-action { - border-width: 1px; - border-style: solid; - border-color: black; - padding: 0.8em; - text-decoration-line: unset; - border-radius: 4px; - box-sizing: border-box; -} - -@media screen and (max-width: 768px) { - .horizontal-wrapper { - flex-direction: column; - } -} diff --git a/assets/css/global.css b/assets/css/global.css index b727f33..f9e895d 100644 --- a/assets/css/global.css +++ b/assets/css/global.css @@ -1,15 +1,15 @@ @import url('fonts.css'); @import url('navigation.css'); @import url('colors.css'); -@import url('content.css'); +@import url('note.css'); html { - background-color: var(--background-color); + background-color: var(--color-background-1); } body { - font-family: 'FormaDJRText', sans-serif; - color: black; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Inter, Ubuntu, sans-serif; + color: var(--color-primary-1); display: flex; flex-direction: column; @@ -35,12 +35,14 @@ footer { width: 100%; padding-bottom: 32px; - padding-top: 64px; - color: dimgray; } a { - color: unset; + color: var(--color-accent); +} + +a:hover { + color: var(--color-accent-hover); } /* Improve readability for smaller text, especially in long paragraphs */ @@ -48,8 +50,8 @@ p, a, ul, ol { - letter-spacing: 0.2px; - line-height: 24px; + line-height: 1.6em; + font-size: 18px; } h1, @@ -58,23 +60,23 @@ h3, h4, h5, h6 { - margin-top: 2em; + margin-top: 1em; margin-bottom: 0.5em; - font-family: 'FormaDJRDisplay', sans-serif; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Inter, Ubuntu, sans-serif; } h1 { - font-size: 3em; -} - -h2 { font-size: 2em; } -h3 { +h2 { font-size: 1.5em; } +h3 { + font-size: 1.2em; +} + img { max-width: 100%; } diff --git a/assets/css/navigation.css b/assets/css/navigation.css index c49ae45..3425172 100644 --- a/assets/css/navigation.css +++ b/assets/css/navigation.css @@ -10,16 +10,13 @@ height: 64px; } -.nav-logo { - display: flex; - align-items: center; +.nav-title { text-decoration: none; - color: black; + color: unset; } -.nav-logo-icon { - height: 48px; - width: 48px; +.nav-title:hover { + color: unset; } .nav-menu { @@ -29,134 +26,3 @@ padding: 0; gap: 32px; } - -.nav-item { - display: flex; -} - -.nav-link { - text-decoration: none; - color: black; -} - -.nav-link:hover { - color: #666; -} - -/* Hamburger Menu */ -.hamburger-toggle { - display: none; -} - -.hamburger { - display: none; - flex-direction: column; - cursor: pointer; - width: 64px; - height: 64px; - justify-content: center; - align-items: center; - background-color: black; - gap: 4px; -} - -.hamburger-line { - width: 20px; - height: 2px; - background-color: white; -} - -.menu-overlay { - position: fixed; - top: 80px; - left: 0; - width: 100%; - height: calc(100% - 80px); - background-color: rgba(0, 0, 0, 0.5); - z-index: 999; - opacity: 0; - visibility: hidden; - cursor: pointer; -} - -/* Mobile Navigation */ -@media screen and (max-width: 768px) { - .hamburger { - display: flex; - } - - .nav-menu { - position: fixed; - left: -100%; - top: 80px; - flex-direction: column; - background-color: var(--background-color); - width: 100%; - z-index: 1000; - gap: 0; - } - - .hamburger-toggle:checked ~ .nav-menu { - left: 0; - } - - .hamburger-toggle:checked ~ .menu-overlay { - opacity: 1; - visibility: visible; - } - - .nav-menu .nav-link { - padding: 16px; - width: 100%; - } -} - -.project-header { - position: relative; - display: inline-block; - margin-top: 96px; -} - -.project-header h1 { - margin-top: 0; -} - -.project-header .breadcrumb-wrapper { - position: absolute; - left: 0; - bottom: 100%; - margin-bottom: 0.5rem; - display: flex; - flex-direction: row; - gap: 8px; -} - -.project-header .breadcrumb-wrapper a { - display: inline-block; -} - -.project-header .breadcrumb-wrapper p { - margin: 0; - display: inline-block; -} - -.project-footer { - box-sizing: border-box; - display: flex; - flex-direction: row; - justify-content: space-between; - - height: 64px; - border-top: 1px solid black; - border-bottom: 1px solid black; - - padding-top: 16px; - padding-bottom: 16px; - margin-top: 96px; -} - -.project-footer div { - display: flex; - flex-direction: row; - align-items: center; -} diff --git a/assets/css/note.css b/assets/css/note.css new file mode 100644 index 0000000..74fd4a7 --- /dev/null +++ b/assets/css/note.css @@ -0,0 +1,12 @@ +.backlink-divider { + color: var(--color-background-2); +} + +.backlink-box { + display: flex; + flex-direction: column; +} + +.backlinks { + +} \ No newline at end of file diff --git a/projects/cmes-mobile/assets/cmes-mobile-app.png b/assets/project/cmes-mobile-app.png similarity index 100% rename from projects/cmes-mobile/assets/cmes-mobile-app.png rename to assets/project/cmes-mobile-app.png diff --git a/projects/the-farmers-dog-trivia/assets/farmers-dog.png b/assets/project/farmers-dog.png similarity index 100% rename from projects/the-farmers-dog-trivia/assets/farmers-dog.png rename to assets/project/farmers-dog.png diff --git a/projects/interchange/assets/interchange-screenshots.png b/assets/project/interchange-screenshots.png similarity index 100% rename from projects/interchange/assets/interchange-screenshots.png rename to assets/project/interchange-screenshots.png diff --git a/projects/power-to-the-people/assets/power-to-the-people.png b/assets/project/power-to-the-people.png similarity index 100% rename from projects/power-to-the-people/assets/power-to-the-people.png rename to assets/project/power-to-the-people.png diff --git a/projects/resonance/assets/resonance-screenshot.png b/assets/project/resonance-screenshot.png similarity index 100% rename from projects/resonance/assets/resonance-screenshot.png rename to assets/project/resonance-screenshot.png diff --git a/projects/sourcebook/assets/sourcebook.png b/assets/project/sourcebook.png similarity index 100% rename from projects/sourcebook/assets/sourcebook.png rename to assets/project/sourcebook.png diff --git a/projects/tad-pool/assets/tad-pool.png b/assets/project/tad-pool.png similarity index 100% rename from projects/tad-pool/assets/tad-pool.png rename to assets/project/tad-pool.png diff --git a/projects/timestamp/assets/timestamp-screenshot.png b/assets/project/timestamp-screenshot.png similarity index 100% rename from projects/timestamp/assets/timestamp-screenshot.png rename to assets/project/timestamp-screenshot.png diff --git a/index.md b/index.md deleted file mode 100644 index 683b81a..0000000 --- a/index.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -title: "Brendan Chen" -layout: default -isIndexPage: 1 ---- - -# Brendan Chen - -I'm Brendan, a recently graduated Software Engineering student who attended Chapman University. I'm currently an associate software engineer at Cargill. I'm also the creator of [OpenAppLock](https://github.com/brendan-ch/OpenAppLock), an open-source time blocker for iOS, and [Interchange](https://interchange.bchen.dev), a free shuttle app for Chapman students. - -I believe that no matter which path an app's development takes, it should be grounded in real experiences. - -Feel free to [say hi](mailto:brendan@bchen.dev)! - -
- View projects - View resume -
- -![Picture of me taken at the Senso-ji Buddhist Temple in Asakusa, Tokyo, Japan](assets/me-1.png "Picture of me taken at the Senso-ji Buddhist Temple in Asakusa, Tokyo, Japan") - diff --git a/notes.html b/notes.html deleted file mode 100644 index e185039..0000000 --- a/notes.html +++ /dev/null @@ -1,23 +0,0 @@ ---- -title: "Notes" -layout: default ---- - -

Notes

- -

I've moved publishing to my [Substack](https://bchendev.substack.com?utm_source=bchen.dev). For reference, old notes remain accessible here.

- -

- -{% assign posts_by_month = site.posts | group_by_exp: "post", "post.date | date: '%B %Y'" %} -{% for month in posts_by_month %} -

{{ month.name }}

- -{% endfor %} diff --git a/projects/cmes-mobile.md b/projects/cmes-mobile.md new file mode 100644 index 0000000..9572adf --- /dev/null +++ b/projects/cmes-mobile.md @@ -0,0 +1,5 @@ +--- +title: Page moved +layout: page_moved +--- +[[CMES Mobile App]] \ No newline at end of file diff --git a/projects/cmes-mobile/index.md b/projects/cmes-mobile/index.md deleted file mode 100644 index a8de11c..0000000 --- a/projects/cmes-mobile/index.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -title: CMES Mobile App -layout: project ---- - -![cmes-mobile-app.png](assets/cmes-mobile-app.png "Screenshots of the CMES app, showing the My Library screen and a web view.") - -**App development project for volunteer organization Techies Without Borders.** I helped implement the CMES mobile app, facilitating the download, viewing and playback of medical education content in resource-constrained countries. - -In the early stages, I built the download screen and business logic, the PDF viewer integration, and background audio playback using native code. Later, I built the native web view to integrate with the [CMES-Pi](https://cmesworld.org/cmes_product-Pi.html) solution, simplifying the business logic while adding support for future edge platforms. - -The app's front-end uses Capacitor and Angular, with several Capacitor plugins in Swift + Java to bundle native functionality. - -This app is actively used in medical facilities in Uganda and Nepal, to name a few. - -[App Store](https://apps.apple.com/us/app/cmes/id1276335909){: .primary-action } -[Google Play](https://play.google.com/store/apps/details?id=org.cmesworld.www.cmes_piandroid_app){: .primary-action } -[Techies Without Borders](https://techieswithoutborders.us/){: .secondary-action } -[CMES Project](https://cmesworld.org/){: .secondary-action } -{: .horizontal-wrapper } diff --git a/projects/dont-wake-sandie.md b/projects/dont-wake-sandie.md new file mode 100644 index 0000000..a83c0b0 --- /dev/null +++ b/projects/dont-wake-sandie.md @@ -0,0 +1,5 @@ +--- +title: Page moved +layout: page_moved +--- +[[Don't Wake Sandie]] \ No newline at end of file diff --git a/projects/interchange.md b/projects/interchange.md new file mode 100644 index 0000000..0c2aa10 --- /dev/null +++ b/projects/interchange.md @@ -0,0 +1,5 @@ +--- +title: Page moved +layout: page_moved +--- +[[Interchange]] \ No newline at end of file diff --git a/projects/interchange/index.md b/projects/interchange/index.md deleted file mode 100644 index 8eb6000..0000000 --- a/projects/interchange/index.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -title: Interchange -layout: project ---- - -![interchange-screenshots.png](assets/interchange-screenshots.png "Screenshots of Interchange.") - -**An iOS app for college transit, currently available for Chapman University.** -View routes, shuttle locations, and estimated arrival times in a sleek, -easy-to-use interface. I built this app using SwiftUI, Node.js and Apollo -GraphQL, with Redis as a primary storage mechanism. - -[Download on the App Store](https://apps.apple.com/us/app/interchange-college-commute/id6739968742){: .primary-action } -[Join the TestFlight](https://testflight.apple.com/join/HbuHfUgW){: .secondary-action } -[Website](https://interchange.bchen.dev/){: .secondary-action } -{: .horizontal-wrapper } diff --git a/projects/power-to-the-people.md b/projects/power-to-the-people.md new file mode 100644 index 0000000..cb3de87 --- /dev/null +++ b/projects/power-to-the-people.md @@ -0,0 +1,5 @@ +--- +title: Page moved +layout: page_moved +--- +[[Power to the People]] \ No newline at end of file diff --git a/projects/power-to-the-people/index.md b/projects/power-to-the-people/index.md deleted file mode 100644 index 1530321..0000000 --- a/projects/power-to-the-people/index.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -title: Power to the People -layout: project ---- - -![power-to-the-people.png](assets/power-to-the-people.png "Screenshots of Power to the People, an iOS app designed to make traffic stops safer.") - -**An iPhone app designed to make traffic stops safer for marginalized communities.** Record interactions with police, assign and text emergency contacts, and be informed of your rights. I worked in a student team of 4, including [David Sohn](https://www.linkedin.com/in/sohn-david/), [Jacob Zamore](https://www.linkedin.com/in/jacob-zamore/), and [Patrick Smith](https://www.linkedin.com/in/patrick-smith-ld/), to prototype and build a proof of concept in 36 hours. The app was selected for the **President's Pick award** at [CruzHacks 2024](https://cruzhacks.com/), the premier hackathon of UC Santa Cruz. - - -[GitHub](https://github.com/brendan-ch/PowerToThePeople){: .primary-action } -[Devpost](https://devpost.com/software/power-to-the-people-lbhxyd){: .secondary-action } -{: .horizontal-wrapper } - -My contribution was the iOS app prototype, of which a demo is shown below. I built the primary user flow of recording a police interaction, simultaneously using the front and back iPhone cameras to capture all angles. Activating the recording also displays the "Know Your Rights" screen, displaying basic dos and don'ts. Finally, I built a way to view previous recordings and share the files using the iOS share sheet. - - diff --git a/projects/resonance.md b/projects/resonance.md new file mode 100644 index 0000000..bd8b5ba --- /dev/null +++ b/projects/resonance.md @@ -0,0 +1,5 @@ +--- +title: Page moved +layout: page_moved +--- +[[Resonance]] \ No newline at end of file diff --git a/projects/resonance/index.md b/projects/resonance/index.md deleted file mode 100644 index 9e275cd..0000000 --- a/projects/resonance/index.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -title: Resonance -layout: project ---- - -![resonance-screenshot.png](assets/resonance-screenshot.png "Screenshot of Resonance") - -Resonance is a cyberpunk-themed game show shooter. Enter the arena, blast your opponents, and become the star of the show. I worked with a student team of 12 to create this game over multiple months. The game was selected as an **IEEE GameSig finalist**. - -*Steam link coming soon!* - -My core role was to implement the game's networking logic using PurrNet, an open-source library for Unity. - -My first project was to implement networking for **Arena**, a free-for-all PVP game mode, where the player with the most eliminations wins. I learned how to isolate game logic on the server and synchronize state on each client. The networked API for Arena is used by every aspect of the game, including the scoreboard UI and spotlight mechanic. Following a pivot in the game’s core direction, I successfully handed this system to another engineer, who implemented a rating system for style points. - -Another project was the **build system**. Having a server dependency and Steam integration meant that the environment differed from development to production. We found it painful to prepare a build for each class-mandated playtest. With the help of Claude, I created a two-step system: an editor script to build and configure dependencies in one step, and a nightly GitHub Actions pipeline. Besides simplifying the build process, this created another positive side effect by ensuring we fixed compiler issues proactively. - -I'm currently working on a client-side prediction model to match other FPS games on the market. - -Even with our team size, the most important thing I learned was how to manage scope and scale. Each one of us pushed ourselves to the limits of our knowledge, going from bare theoretical understanding to practical working implementations. The goal was never to get things right on the first try; it was to learn and realize new ideas in multiple passes. diff --git a/projects/sourcebook.md b/projects/sourcebook.md new file mode 100644 index 0000000..5e2b73b --- /dev/null +++ b/projects/sourcebook.md @@ -0,0 +1,5 @@ +--- +title: Page moved +layout: page_moved +--- +[[Sourcebook]] \ No newline at end of file diff --git a/projects/tad-pool.md b/projects/tad-pool.md new file mode 100644 index 0000000..7531945 --- /dev/null +++ b/projects/tad-pool.md @@ -0,0 +1,5 @@ +--- +title: Page moved +layout: page_moved +--- +[[Tad-Pool]] \ No newline at end of file diff --git a/projects/tad-pool/index.md b/projects/tad-pool/index.md deleted file mode 100644 index 2397422..0000000 --- a/projects/tad-pool/index.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -title: Tad-Pool -layout: project ---- - -![tad-pool.png](assets/tad-pool.png "Screenshots of Tad-Pool, a carpooling app for college students.") - -**A mobile app designed to make carpooling easier for college students.** Find -carpools based on time and location, and get rewarded for helping to reduce CO2 -emissions. I worked with [Jazmine Stanek](https://www.linkedin.com/in/vjazminestanek/) -and [Isabelle Woo](https://www.linkedin.com/in/isabellewoo/) to create the UI/UX -design using Figma and FigJam, in a period of 24 hours for -[FullyBeyond 2024](https://fullybeyond.acmcsuf.com/). - -The project reached the finalist judging stage. - -[High-fidelity design](https://www.figma.com/design/nTKCcwftKrg27wlP5mmy9e/Tad-Pool-Design?node-id=13-1837&node-type=canvas&t=YKuVvM6RAPs4hTIo-11){: .primary-action } -[Low-fidelity design](https://www.figma.com/design/nTKCcwftKrg27wlP5mmy9e/Tad-Pool-Design?node-id=0-1&node-type=canvas&t=YKuVvM6RAPs4hTIo-11){: .secondary-action } -[FigJam board](https://www.figma.com/board/Dct7GuhKFYq8maw0KoAVBV/Product-Brainstorm-FullyBeyond?node-id=0-1&node-type=canvas&t=g7RKLLo5IoU84ndk-11){: .secondary-action } -[Devpost](https://devpost.com/software/tad-pool){: .secondary-action } -{: .horizontal-wrapper } diff --git a/projects/teech-ai-cal-hacks-12.md b/projects/teech-ai-cal-hacks-12.md new file mode 100644 index 0000000..f53d974 --- /dev/null +++ b/projects/teech-ai-cal-hacks-12.md @@ -0,0 +1,5 @@ +--- +title: Page moved +layout: page_moved +--- +[[teech.ai]] \ No newline at end of file diff --git a/projects/teech-ai-cal-hacks-12/index.md b/projects/teech-ai-cal-hacks-12/index.md deleted file mode 100644 index 4a1d516..0000000 --- a/projects/teech-ai-cal-hacks-12/index.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -title: teech.ai -layout: project ---- - - - -**A proof-of-concept tutoring app for students learning math.** Using the phone camera, the app sees and understands math problems, guiding students through problems with hints and step-by-step questions. We added text-to-speech (TTS) to give our app a voice, further engaging students and making it feel like a more personal experience. - -[Tri Vu](https://www.linkedin.com/in/tri-q-vu/) built a web interface prototype and Python-based backend utilizing the Gemini Vision API and Fish Audio for TTS. - -I built a native proof-of-concept using SwiftUI, AVFoundation, and other native frameworks. In the app, I built a chat and camera interface, integrating with Tri's backend by sending image and prompt data. Swiping to the right reveals the user's chat history, which is also continuously synced with the backend. Design-wise, I decided to use this gesture-based approach in order to bring the camera interface front and center. - -The app was built in 48 hours for **Cal Hacks 12.0**, the world's largest collegiate hackathon. - -[GitHub](https://github.com/brendan-ch/teecher-ios){: .primary-action } -[Devpost](https://devpost.com/software/teech-ai){: .secondary-action } -[Cal Hacks](https://www.calhacks.io){: .secondary-action } -{: .horizontal-wrapper } diff --git a/projects/the-farmers-dog-trivia.md b/projects/the-farmers-dog-trivia.md new file mode 100644 index 0000000..7df1c91 --- /dev/null +++ b/projects/the-farmers-dog-trivia.md @@ -0,0 +1,5 @@ +--- +title: Page moved +layout: page_moved +--- +[[The Farmer's Dog Trivia Game]] \ No newline at end of file diff --git a/projects/timestamp.md b/projects/timestamp.md new file mode 100644 index 0000000..f2575cc --- /dev/null +++ b/projects/timestamp.md @@ -0,0 +1,6 @@ +--- +title: Timestamp +layout: page_moved +--- +[[Timestamp]] + diff --git a/projects/timestamp/index.md b/projects/timestamp/index.md deleted file mode 100644 index c2b64d9..0000000 --- a/projects/timestamp/index.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -title: Timestamp -layout: project ---- - -![Screenshot of the Timestamp app and the settings window.](assets/timestamp-screenshot.png) - -A simple, unintrusive Pomodoro timer for macOS which lives in the menu bar. I built it with SwiftUI and made it open source. - -[Download the app](https://github.com/brendan-ch/timestamp/releases){: .primary-action } -[View the code](https://github.com/brendan-ch/timestamp){: .secondary-action } -{: .horizontal-wrapper }