Skip to content
aniqatcPublic

About

đź“’ My personal space on the web.

Topics

Resources

Stars

2 stars

Watchers

1 watching

Forks

Repository files navigation

aniqa.dev

Aniqa's portfolio, lab, and app reviews, built with Astro and hosted on Vercel.

The lab lives at /lab. Pages are static except likes and sign-ups.

Portfolio Lab
Portfolio preview Lab preview

Entry Open Graph images are in public/og/. After changing a title, blurb, or screenshot, run npm run og and include the updated images.

Tech

  • Astro 7, strict TypeScript, plain CSS, Sätteri, Vercel adapter
  • Fontsource: Bricolage Grotesque, Geist, Geist Mono
  • Upstash Redis for likes; Buttondown for sign-ups
  • Playwright for screenshots and share cards
  • p5.js and Three.js for experiments that need them

Features

  • Portfolio case studies and “Building now” section
  • Lab archive by year, favorites, random entry, likes, and mouse-only hover previews
  • Live experiment stages with optional themes and controls
  • Reviews with scores, app screenshots, and shareable scorecards
  • Generated Open Graph images, page transitions, and an animated calendar pet

Pet calendar

The default is auto in src/lib/pets.ts. Set PET there to a pet name to pin one.

Dates Pet
Jan 1–7 Party
Jan 8–31 Penguin
Feb 1–14 / Feb 15–29 Heart / mochi
March / April / May / June Chick / bunny / sprout / bee
July–August / September / October / November / December Frog / owl / pumpkin / acorn / snowball

Date overrides: Feb 27 cupcake; Mar 27, May 5, June 26, Oct 18 heart; June 30 and Sep 20 cupcake; Oct 31 ghost; Dec 25 tree; Dec 31 party. Mother's Day and Father's Day use party; Eid uses moon; Diwali uses diya for all five days (2 either side of the main date); Lunar New Year uses lantern. Moving-date rules and calendars are in src/lib/pets.ts.

Click the dot by the site name to reveal the pet. It follows pointer movement or taps. Reduced-motion settings reduce its movement and animation.

Accessibility

  • Semantic links and controls, accessible names, and visible keyboard focus
  • Hover previews only on mouse; links work on touch screens
  • Reduced-motion preferences disable or reduce animations

Project structure

src/content/projects/      Portfolio case studies
src/content/experiments/   Lab entries and studies
src/content/reviews/       App reviews
src/components/            Shared Astro components
src/lib/                    Content helpers and site data
src/pages/                  Routes and API endpoints
src/scripts/                Browser interactions
src/styles/                 Tokens and shared styles
templates/                  Entry scaffolds
scripts/                    Build and image tools
public/og/                  Generated preview images

Key concepts

  • One folder per entry, with index.md; schemas are in src/content.config.ts.
  • Lab entries with sketch.ts or sketch.astro run on the page. Others link out.
  • stage: frame is fixed-ratio; stage: fit grows to fit studies.
  • themes: true adds day/night controls to a stage.
  • draft: true hides entries from production; favorite: true pins a lab entry.
  • Projects and lab entries need screenshot.png and descriptive screenshotAlt.

Setup

Requires Node.js 22.22 or newer.

npm install
cp .env.example .env.local
npx playwright install chromium
npm run dev

The site builds without credentials. Add the variables needed for these features:

Variable Used for
BUTTONDOWN_API_KEY Email sign-ups
UPSTASH_REDIS_REST_URL Likes database URL
UPSTASH_REDIS_REST_TOKEN Likes database token
GITHUB_TOKEN Optional GitHub API reads, such as star counts
VERCEL_DEPLOY_HOOK GitHub Actions secret for daily star refresh; not an .env.local variable

Upstash also accepts KV_REST_API_URL and KV_REST_API_TOKEN as aliases.

NPM scripts

Command What it does
npm run dev Start the site at localhost:4321 (foreground; stop with Ctrl+C).
npm run start Alias for npm run dev.
npm run build Type-check and build.
npm run check Run Astro checks.
npm run lint Run ESLint.
npm run format / format:check Format files / check formatting.
npm run new Scaffold a project, experiment, or review.
npm run screenshots Capture content screenshots; pass slugs to select entries.
npm run og Generate Open Graph images.
npm run scorecard -- <slug> Generate a review scorecard.

There is no preview script for the Vercel adapter.

Adding content

Each entry is a folder under src/content/. Start with the matching command below, then:

  1. Edit the new folder's index.md: complete its frontmatter and write-up.
  2. Add screenshot.png and describe what it shows in screenshotAlt.
  3. Run npm run og, then check the page locally with npm run dev.

The scaffold prints the new folder path and the next steps. Use draft: true to keep a project or experiment out of production while you work. Reviews start as drafts automatically.

Portfolio project

npm run new -- --kind project --title "Title" --slug slug
  1. Edit src/content/projects/<slug>/index.md. Fill in released, type, stack, blurb, summary, and order.
  2. Write Why, What it does, and What I learned in first person. Keep each point specific and short. Add Hardest part or dated Revisited only when you have something useful to add.
  3. Add the screenshot and alt text. The screenshot script captures the live site in dark mode.

Lab note that links out

npm run new -- --kind experiment --sketch none --title "Title" --slug slug
  1. In src/content/experiments/<slug>/index.md, fill in live (the site host) and repo (the GitHub repository name, if public).
  2. Write Why I built it and What I learned. Keep the notes brief and specific. If this is a CodePen migration, put its URL in v1 and describe the migration in Revisited.
  3. Run npm run screenshots -- <slug> to capture the live site in light mode. Add alt text describing the screenshot.

On-site experiment

npm run new -- --kind experiment --sketch canvas --title "Title" --slug slug
  1. Choose canvas, css, p5, or three in --sketch. The scaffold creates sketch.ts for canvas, p5, and Three.js, or sketch.astro for CSS art. Install p5.js or Three.js if needed, then restart the dev server.
  2. In index.md, fill in the type, stack, summary, and optional hint. Write an Idea and a few short Notes about what you tried, tuned, or learned.
  3. Set stage: frame for a fixed stage or stage: fit when the stage should grow with the sketch. Capture the screenshot with npm run screenshots -- <slug> and add alt text.

CSS or JavaScript study

npm run new -- --kind experiment --sketch study --title "Title" --slug slug
  1. Edit sketch.astro to build the study. Use the shared controls and styles in src/styles/demo.css.
  2. In index.md, set type to CSS study or JS study, and fill in the summary and hint. Write an Idea and Notes that explain the concept, the technique, and what you noticed while testing it.
  3. For a CodePen migration, put the original URL in v1 and add a dated Revisited note. Capture the screenshot with npm run screenshots -- <slug> and add alt text.

App review

npm run new -- --kind review --app "App name" --maker handle --live example.com
  1. Fill in the review's date, triedOn, scores, verdict, and brand colour in index.md.
  2. Write First look, What I liked, Small ideas, and Who it's for. Use concrete details from trying the app; keep suggestions kind and specific. To show a detail, put a screenshot in the review folder and add it to the point, either framed under it or as a picture note in the text (see Pictures in a review).
  3. For a web app, run npm run screenshots -- reviews/<slug> to capture the app and its icon. For a phone or tablet app, add screenshots from the device and set device to phone or tablet; for a Mac app, see Mac apps. Optional price, version and platforms show with the facts.
  4. Run npm run scorecard -- <slug> to make the share image. Check the draft locally, remove draft: true when ready, then run npm run og for the review's link preview.

The Try it card at the end of a review says “Give it a go, and if you like it, let them know. Early feedback means a lot when you’re building something new.” For a review where that doesn’t fit, like a mixed one or a big company’s app, set tryIt in its frontmatter to say something else.

The home page intro shows one review: the newest, under Reviewing. To keep one there instead, add featured: true to its frontmatter and it shows under Hooked on (the newest featured one wins if there are several).

Game review

Games use the same reviews, with their own scores and a few different labels. Start one with:

npm run new -- --kind review --game --app "Game name" --maker studiohandle --live https://store.steampowered.com/app/…

(or run npm run new, pick review, and answer game when it asks). That copies templates/review-game/ and sets kind: game, which changes:

App Game
Scores First impression, Onboarding, Usefulness, Ease of use, Pricing / value First impression, Learning curve, Fun, Feel, Pricing / value
Score keys onboarding, usefulness, easeOfUse learningCurve, fun, feel
Facts Tried on Played on, plus Time played from played: 15 hours
Eyebrow App review 01 Game review 01
Star on the tile Still using it Still playing it
  • What the game scores mean: Learning curve is how quickly it clicked and whether the tutorial helped or got in the way; Fun is whether it's actually fun to play; Feel is the controls, responsiveness and performance; Pricing / value is the price against the hours you got out of it (replayability goes here).
  • Screenshot: for a PC or console game, device: screen shows one plain 16:9 screenshot with no device around it: put an in-game shot (1920 Ă— 1080 or larger) in screenshot.png. A phone, iPad or Mac game uses phone, tablet or desktop like an app.
  • Logo: the game's icon, or its store capsule art cropped square, in logo.png.
  • Link: set live to the store page; it reads Steam ↗, itch.io ↗ or App Store ↗ on its own.
  • Writing: the same sections (First look, What I liked, Small ideas, Who it's for). Keep story spoilers out, or flag them first. "Who it's for" can say what it's like ("if you liked X, you'll like this").
  • Big studios: the Try it card's "Early feedback means a lot" is for indie games; for a big studio's game, set tryIt to something else.
  • Mixing up scores fails the build: a game needs learningCurve, fun and feel, and an app onboarding, usefulness and easeOfUse, so a game without kind: game (or the reverse) gets a clear error.
  • When the first game goes up, change the /reviews lede in src/pages/reviews/index.astro from "I try apps…" to "I try apps and games…".

Updating a review

When an app changes after you've reviewed it (the maker took your feedback, or a gripe went away), add to the review instead of rewriting it, so readers can see what changed and what you thought before.

  1. Date it. Add updated: YYYY-MM-DD to the frontmatter. It shows under the review's date in the facts, and search engines get it as the modified date. Bump version (and triedOn, if your Mac or phone changed).

  2. Write an Update section right after the TL;DR, so returning readers see it first. Start it with the date and version in italics; that line shows small and grey, like the facts. Say what changed and which score moved. For a second update later, add a new ## Update above the old one, newest first.

    ## Update
    
    _Dec 12, 2026 · version 1.4_
    
    @capt_sherman shipped a Health tab, so water and the eye breaks now live together. That was my main gripe, so
    ease of use goes from 4 to 5.
  3. Change the scores in the frontmatter. Don't strike them out; the Update says what moved and why.

  4. Strike what's no longer true with ~~ ~~, and put a tag after it in backticks. Keep it to the sentence or clause that changed, not whole paragraphs; it shows grey and still readable.

    Water sits with the Pomodoro timer, ~~which is actually my main gripe~~ `Fixed in 1.4`. That being said…
  5. Tag shipped ideas in Small ideas without striking them, since the idea is still what you asked for: `Shipped in 1.4` at the end of the point. Both tags get a âś“ and look the same; only the word changes.

  6. The tile: for 30 days after updated, the review's tile on /reviews and the home page gets a refresh badge, explained by the legend in the All reviews heading. It drops off at the first deploy after that.

  7. Refresh the images: npm run scorecard -- <slug> and npm run og, so the share card and link preview show the new scores. On X, quote-post your original post with the update.

Pictures in a review

There are two ways to show a picture in a review's notes. Both open it full size when clicked (or focused and opened with Enter), with its caption under it, and you can mix them in one review. Crop to the part that matters.

Framed, under the point: the picture sits in a narrow frame below the text. Leave a blank line before it.

1. **Make it yours.** There are 21 tabs, but you can remove what you don't need.

   ![The tab grid, with the Pet care tab selected](./tabs.png)

Add a caption with an italic line straight after the image. It shows in a strip along the bottom of the frame.

![The tab grid, with the Pet care tab selected](./tabs.png)
_The tab grid, with Pet care open_

Two images on one line sit side by side, for phone screens, and share one caption.

![The empty state](./phone-before.png) ![The first entry](./phone-after.png)
_Before and after the first entry_

Picture note, in the text: give the image the title "note" and put it right after the words it shows. It becomes a small chip in the line, so the sentence keeps reading normally.

1. **Make it yours.** There are 21 tabs ![The tab grid](./tabs.png 'note'), but you can remove what you don't need.

Add a caption after a colon in the title. It shows under the picture when it opens.

1. **The pet.** Bombay ![The pet care panel](./pet.png 'note: Bombay, between her food and water bowls') peeks
   out of the notch.
You write It shows as Caption from
![alt](./file.png) A framed picture under the point An italic line after it
![alt](./a.png) ![alt](./b.png) Two framed pictures side by side An italic line after them
![alt](./file.png "note") A chip in the text that opens the picture None
![alt](./file.png "note: A caption") A chip in the text that opens the picture The text after note:

The alt text describes the picture for screen readers either way; any other title leaves a picture framed.

Mac apps

Set device: desktop. screenshot.png is only the app, with no background, and the site draws the Mac screen around it: the wallpaper (tinted with brand), the menu bar, the notch, and the Dock. The image is treated as a 2Ă— (Retina) capture and shown at half its pixel size, so it is never stretched.

desktop What it shows How to capture
window (default) The window in the middle of a MacBook, with a Dock Cmd+Shift+4, Space, then Option-click the window (no shadow)
menubar A popover hanging under its menu bar icon Cmd+Shift+4, Space, then click the popover, or a tight drag; leave out the icon
notch A panel growing out of the notch Drag-select from the top edge of the screen around the panel

Add the app icon as logo.png; it becomes the icon in the Dock and the menu bar (without it, the first letter on the brand colour). The site adds a soft shadow; set shadow: false if the capture already has one.

Changelog

October 2026 — v2

  • Rebuilt the portfolio in Astro; added the lab, reviews, likes, pets, and generated share images.

2025 — v1

  • Published the original React portfolio. See the react-v1 tag.

License

Code is MIT. Writing, experiments, and images are © Aniqa, all rights reserved.

About

đź“’ My personal space on the web.

Topics

Resources

Stars

2 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages