apple-inspired personal website
See the codei'm obsessed with re-creating apple products. this is a macos-inspired personal website featuring a full desktop environment with multiple apps.
a macos sierra 10.12 themed desktop with:
notes - apple notes clone for my personal website content
messages - imessage clone with ai-powered conversations
iterm - terminal emulator
textedit - plain text editor
preview - image and pdf viewer
docs/document-apps.mdfinder - file browser
calendar - apple calendar clone
photos - apple photos clone
games - an Apple Games-inspired library with six playable games
settings - system preferences
weather - weather forecast app
/weatherdocs/weather-scenes.mdmobile support is intentionally app-specific. supported apps render as
touch-optimized, full-screen experiences; every unsupported app route redirects
to /notes on mobile. Unsupported apps are desktop-only components and do not
retain separate mobile presenters.
| app | in Dock by default | mobile support | mobile route behavior |
|---|---|---|---|
| Finder | yes | no | redirects to /notes |
| Notes | yes | yes | opens Notes |
| Messages | yes | yes | opens Messages |
| Photos | yes | yes | opens Photos |
| Music | yes | yes | opens Music |
| Calendar | yes | yes | opens Calendar |
| Weather | no | no | redirects to /notes |
| iTerm | yes | no | redirects to /notes |
| Games | yes | no | redirects to /notes |
| Settings | yes | no | redirects to /notes |
| TextEdit | no | no | redirects to /notes |
| Preview | no | no | redirects to /notes |
supported mobile apps include:
the app uses next.js app router with a route group for the desktop environment. on desktop screens, all apps render in windows on a shared desktop. on mobile, apps display fullscreen with navigation.
notes use a session-based architecture:
messages are client-side only:
photos use supabase storage:
games uses a browser-local identity and supabase-backed chess matches:
chess.js; the computer search runs in a web workerthe app is built with:
the app uses supabase for the postgresql database with row-level security policies to control access to public and private notes.
database schema:
the notes table stores all notes with these fields:
id (uuid): unique identifiertitle (text): note titlecontent (text): markdown contentsession_id (uuid): links notes to browser sessionspublic (boolean): controls visibilityslug (text): url-friendly identifiercategory (text): optional categorizationemoji (text): note iconcreated_at (timestamp): when the note was createdpublic notes are cached for 24 hours using next.js isr. private notes are always real-time.
to manually revalidate public notes:
set REVALIDATE_TOKEN in environment variables, then:
# revalidate sidebar (when adding/removing public notes)
curl -X POST "https://yourdomain.com/notes/revalidate" \
-H "Content-Type: application/json" \
-H "x-revalidate-token: your-token" \
-d '{"layout": true}'
# revalidate specific note (when updating content)
curl -X POST "https://yourdomain.com/notes/revalidate" \
-H "Content-Type: application/json" \
-H "x-revalidate-token: your-token" \
-d '{"slug": "note-slug"}'
or redeploy on vercel to refresh all pages.
REVALIDATE_TOKEN must stay server-side only. do not expose it via NEXT_PUBLIC_* variables.
upload photos directly from your iphone using the share sheet:
https://yourdomain.com/api/photos/uploadx-api-key: <your-PHOTOS_UPLOAD_API_KEY>{ "image": [base64], "timestamp": [formatted date] }when you share a photo, the shortcut uploads it to supabase storage and ai automatically categorizes it into collections (flowers, food, friends).
git clone https://github.com/alanagoyal/alanagoyal
this project uses supabase as a backend. to set up the database:
alternatively, use the supabase cli to apply the complete migration history. this is required for online chess because the games migrations create the private match table and its server-only matchmaking function:
supabase db push
grab the project url and anon key from the api settings and put them in a new .env.local file in the root directory:
# supabase (required for notes and photos)
NEXT_PUBLIC_SUPABASE_URL="<your-supabase-url>"
NEXT_PUBLIC_SUPABASE_ANON_KEY="<your-anon-key>"
SUPABASE_SERVICE_ROLE_KEY="<your-service-role-key>"
# braintrust (required for messages ai)
BRAINTRUST_API_KEY="<your-braintrust-api-key>"
# photos upload (required for ios shortcut)
PHOTOS_UPLOAD_API_KEY="<generate-random-key>"
OPENAI_API_KEY="<your-openai-api-key>"
# site config (optional)
NEXT_PUBLIC_SITE_URL="https://yourdomain.com"
REVALIDATE_TOKEN="<your-revalidate-token>"
notes:
GITHUB_TOKEN is optional but helps avoid rate limits when using iterm/finder github integrationSUPABASE_SERVICE_ROLE_KEY is needed server-side for photo uploads and online chess; never expose it with a NEXT_PUBLIC_ prefixOPENAI_API_KEY is used for ai photo categorizationnpm install
run the application in the command line and it will be available at http://localhost:3000.
npm run dev
with BRAINTRUST_API_KEY configured in .env.local, run the Messages group-chat behavior eval:
npm run eval:chat
the eval exercises response routing, waiting for the human, conversation wrap-up, schema validity, repetition, and texting brevity against the same prompt, tools, and model used by the production chat route.
deploy using vercel
notes support github flavored markdown (gfm) with interactive features. here's what you can use:
# heading 1
## heading 2
### heading 3
**bold text**
*italic text*
~~strikethrough~~
`inline code`
unordered lists:
- item one
- item two
- nested item
- another nested item
ordered lists:
1. first item
2. second item
3. third item
task lists are interactive - click checkboxes to toggle completion:
- [ ] task to do
- [x] completed task
- [ ] another task
the app automatically updates the markdown when you click checkboxes, so your progress is saved.
create tables using standard markdown table syntax. tables render with a styled dark theme:
| book | author | year read |
|------|--------|-----------|
| the great gatsby | f. scott fitzgerald | 2023 |
| 1984 | george orwell | 2024 |
this renders as:
| book | author | year read |
|---|---|---|
| the great gatsby | f. scott fitzgerald | 2023 |
| 1984 | george orwell | 2024 |
table features:
[link text](https://example.com)
all links automatically open in new tabs for better navigation.
inline code: use backticks for inline code
code blocks: use triple backticks for multi-line code
```javascript
function hello() {
console.log("hello world");
}
```
> this is a blockquote
> it can span multiple lines
paste images directly into notes by copying any image (screenshot, file, etc.) and pressing ctrl+v (or cmd+v on mac). images are automatically uploaded to supabase storage and inserted as markdown.
you can also manually add images:

supported formats: jpeg, png, gif, webp (including animated gifs) file size limit: 5mb images are automatically resized to fit the note width while maintaining aspect ratio
---
licensed under the mit license.
601 followers · starred Jun 2026
347 followers · starred Jul 2024
459 followers · starred Jul 2024
950 followers · starred Nov 2024
apple-inspired personal website
See the codei'm obsessed with re-creating apple products. this is a macos-inspired personal website featuring a full desktop environment with multiple apps.
a macos sierra 10.12 themed desktop with:
notes - apple notes clone for my personal website content
messages - imessage clone with ai-powered conversations
iterm - terminal emulator
textedit - plain text editor
preview - image and pdf viewer
docs/document-apps.mdfinder - file browser
calendar - apple calendar clone
photos - apple photos clone
games - an Apple Games-inspired library with six playable games
settings - system preferences
weather - weather forecast app
/weatherdocs/weather-scenes.mdmobile support is intentionally app-specific. supported apps render as
touch-optimized, full-screen experiences; every unsupported app route redirects
to /notes on mobile. Unsupported apps are desktop-only components and do not
retain separate mobile presenters.
| app | in Dock by default | mobile support | mobile route behavior |
|---|---|---|---|
| Finder | yes | no | redirects to /notes |
| Notes | yes | yes | opens Notes |
| Messages | yes | yes | opens Messages |
| Photos | yes | yes | opens Photos |
| Music | yes | yes | opens Music |
| Calendar | yes | yes | opens Calendar |
| Weather | no | no | redirects to /notes |
| iTerm | yes | no | redirects to /notes |
| Games | yes | no | redirects to /notes |
| Settings | yes | no | redirects to /notes |
| TextEdit | no | no | redirects to /notes |
| Preview | no | no | redirects to /notes |
supported mobile apps include:
the app uses next.js app router with a route group for the desktop environment. on desktop screens, all apps render in windows on a shared desktop. on mobile, apps display fullscreen with navigation.
notes use a session-based architecture:
messages are client-side only:
photos use supabase storage:
games uses a browser-local identity and supabase-backed chess matches:
chess.js; the computer search runs in a web workerthe app is built with:
the app uses supabase for the postgresql database with row-level security policies to control access to public and private notes.
database schema:
the notes table stores all notes with these fields:
id (uuid): unique identifiertitle (text): note titlecontent (text): markdown contentsession_id (uuid): links notes to browser sessionspublic (boolean): controls visibilityslug (text): url-friendly identifiercategory (text): optional categorizationemoji (text): note iconcreated_at (timestamp): when the note was createdpublic notes are cached for 24 hours using next.js isr. private notes are always real-time.
to manually revalidate public notes:
set REVALIDATE_TOKEN in environment variables, then:
# revalidate sidebar (when adding/removing public notes)
curl -X POST "https://yourdomain.com/notes/revalidate" \
-H "Content-Type: application/json" \
-H "x-revalidate-token: your-token" \
-d '{"layout": true}'
# revalidate specific note (when updating content)
curl -X POST "https://yourdomain.com/notes/revalidate" \
-H "Content-Type: application/json" \
-H "x-revalidate-token: your-token" \
-d '{"slug": "note-slug"}'
or redeploy on vercel to refresh all pages.
REVALIDATE_TOKEN must stay server-side only. do not expose it via NEXT_PUBLIC_* variables.
upload photos directly from your iphone using the share sheet:
https://yourdomain.com/api/photos/uploadx-api-key: <your-PHOTOS_UPLOAD_API_KEY>{ "image": [base64], "timestamp": [formatted date] }when you share a photo, the shortcut uploads it to supabase storage and ai automatically categorizes it into collections (flowers, food, friends).
git clone https://github.com/alanagoyal/alanagoyal
this project uses supabase as a backend. to set up the database:
alternatively, use the supabase cli to apply the complete migration history. this is required for online chess because the games migrations create the private match table and its server-only matchmaking function:
supabase db push
grab the project url and anon key from the api settings and put them in a new .env.local file in the root directory:
# supabase (required for notes and photos)
NEXT_PUBLIC_SUPABASE_URL="<your-supabase-url>"
NEXT_PUBLIC_SUPABASE_ANON_KEY="<your-anon-key>"
SUPABASE_SERVICE_ROLE_KEY="<your-service-role-key>"
# braintrust (required for messages ai)
BRAINTRUST_API_KEY="<your-braintrust-api-key>"
# photos upload (required for ios shortcut)
PHOTOS_UPLOAD_API_KEY="<generate-random-key>"
OPENAI_API_KEY="<your-openai-api-key>"
# site config (optional)
NEXT_PUBLIC_SITE_URL="https://yourdomain.com"
REVALIDATE_TOKEN="<your-revalidate-token>"
notes:
GITHUB_TOKEN is optional but helps avoid rate limits when using iterm/finder github integrationSUPABASE_SERVICE_ROLE_KEY is needed server-side for photo uploads and online chess; never expose it with a NEXT_PUBLIC_ prefixOPENAI_API_KEY is used for ai photo categorizationnpm install
run the application in the command line and it will be available at http://localhost:3000.
npm run dev
with BRAINTRUST_API_KEY configured in .env.local, run the Messages group-chat behavior eval:
npm run eval:chat
the eval exercises response routing, waiting for the human, conversation wrap-up, schema validity, repetition, and texting brevity against the same prompt, tools, and model used by the production chat route.
deploy using vercel
notes support github flavored markdown (gfm) with interactive features. here's what you can use:
# heading 1
## heading 2
### heading 3
**bold text**
*italic text*
~~strikethrough~~
`inline code`
unordered lists:
- item one
- item two
- nested item
- another nested item
ordered lists:
1. first item
2. second item
3. third item
task lists are interactive - click checkboxes to toggle completion:
- [ ] task to do
- [x] completed task
- [ ] another task
the app automatically updates the markdown when you click checkboxes, so your progress is saved.
create tables using standard markdown table syntax. tables render with a styled dark theme:
| book | author | year read |
|------|--------|-----------|
| the great gatsby | f. scott fitzgerald | 2023 |
| 1984 | george orwell | 2024 |
this renders as:
| book | author | year read |
|---|---|---|
| the great gatsby | f. scott fitzgerald | 2023 |
| 1984 | george orwell | 2024 |
table features:
[link text](https://example.com)
all links automatically open in new tabs for better navigation.
inline code: use backticks for inline code
code blocks: use triple backticks for multi-line code
```javascript
function hello() {
console.log("hello world");
}
```
> this is a blockquote
> it can span multiple lines
paste images directly into notes by copying any image (screenshot, file, etc.) and pressing ctrl+v (or cmd+v on mac). images are automatically uploaded to supabase storage and inserted as markdown.
you can also manually add images:

supported formats: jpeg, png, gif, webp (including animated gifs) file size limit: 5mb images are automatically resized to fit the note width while maintaining aspect ratio
---
licensed under the mit license.
601 followers · starred Jun 2026
347 followers · starred Jul 2024
459 followers · starred Jul 2024
950 followers · starred Nov 2024