{"id":50609829,"url":"https://github.com/ngxtm/say-hi","last_synced_at":"2026-06-06T02:30:48.402Z","repository":{"id":353735012,"uuid":"1212153154","full_name":"ngxtm/say-hi","owner":"ngxtm","description":"Browser-based hand frame camera app using MediaPipe Hand Landmarker, Vite, and TypeScript.","archived":false,"fork":false,"pushed_at":"2026-04-25T08:55:58.000Z","size":428,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-25T10:17:19.234Z","etag":null,"topics":["browser-camera","canvas","computer-vision","frontend","gesture-detection","hand-tracking","mediapipe","typescript","vite","webcam"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ngxtm.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-16T05:37:59.000Z","updated_at":"2026-04-25T08:56:01.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/ngxtm/say-hi","commit_stats":null,"previous_names":["ngxtm/say-hi"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/ngxtm/say-hi","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ngxtm%2Fsay-hi","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ngxtm%2Fsay-hi/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ngxtm%2Fsay-hi/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ngxtm%2Fsay-hi/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ngxtm","download_url":"https://codeload.github.com/ngxtm/say-hi/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ngxtm%2Fsay-hi/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33967639,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-06T02:00:07.033Z","response_time":107,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["browser-camera","canvas","computer-vision","frontend","gesture-detection","hand-tracking","mediapipe","typescript","vite","webcam"],"created_at":"2026-06-06T02:30:46.899Z","updated_at":"2026-06-06T02:30:48.378Z","avatar_url":"https://github.com/ngxtm.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Hand Frame Portal\n\n![Vite](https://img.shields.io/badge/Vite-7.x-646CFF?logo=vite\u0026logoColor=white)\n![TypeScript](https://img.shields.io/badge/TypeScript-5.x-3178C6?logo=typescript\u0026logoColor=white)\n![MediaPipe](https://img.shields.io/badge/MediaPipe-Tasks%20Vision-0A84FF)\n![License](https://img.shields.io/badge/License-See%20LICENSE-black)\n\nHand Frame Portal is a browser-based camera experience built with Vite and TypeScript. It uses MediaPipe Hand Landmarker and the Canvas 2D API to detect hands in real time, recognize a hand framing gesture, freeze the scene, and let the user capture, preview, and download an image.\n\nThe project is intentionally small and focused: a single-page web app with no backend, no framework runtime, and a UI layered directly on top of a fullscreen canvas.\n\n## Features\n\n- Real-time hand tracking in the browser\n- Visual hand landmark and connection rendering on a fullscreen canvas\n- Gesture-based frame freeze flow\n- Hold-to-freeze interaction for more stable detection\n- Configurable capture delay: instant, 3 seconds, 5 seconds, or 10 seconds\n- Preview modal before saving the captured image\n- PNG download flow for captured output\n- Reset action to restart the experience quickly\n- Mobile-friendly fullscreen layout with responsive controls\n\n## Tech Stack\n\n- Vite\n- TypeScript\n- `@mediapipe/tasks-vision`\n- Canvas 2D\n- Browser camera APIs via `navigator.mediaDevices.getUserMedia`\n\n## How It Works\n\nAt a high level, the app does the following:\n\n1. Requests camera access from the browser.\n2. Loads the MediaPipe Hand Landmarker runtime and hand model.\n3. Reads frames from the live video stream.\n4. Detects hand landmarks in real time.\n5. Builds and stabilizes a polygon from the detected hand pose.\n6. Freezes the current scene when the user holds the framing gesture steadily.\n7. Lets the user start a delayed capture, preview the result, and download it.\n\nThe UI is rendered as a combination of:\n\n- a fullscreen canvas for live drawing and image composition\n- lightweight DOM controls for status, capture options, reset, and preview\n\n## Requirements\n\nBefore running the project, make sure you have:\n\n- Node.js 18 or newer recommended\n- npm available in your environment\n- A modern browser with camera support\n- Permission to access a webcam\n- Internet access to load MediaPipe assets from remote URLs\n\n## Local Development\n\nInstall dependencies:\n\n```bash\nnpm install\n```\n\nStart the development server:\n\n```bash\nnpm run dev\n```\n\nVite will print a local development URL in the terminal. Open that URL in your browser and allow camera access when prompted.\n\n## Production Build\n\nCreate a production build:\n\n```bash\nnpm run build\n```\n\nPreview the built app locally:\n\n```bash\nnpm run preview\n```\n\n## Deployment\n\nThis project is a static frontend application, so the recommended production setup is a Docker multi-stage build that compiles the app with Node.js and serves the final `dist/` output through Nginx.\n\nAuto deploy smoke test: this line is intentionally safe to change when validating Dokploy watch path triggers.\n\n### Dokploy Deployment\n\nRecommended target:\n\n- Platform: Dokploy\n- Source: GitHub repository\n- Build type: `Dockerfile`\n- Runtime server: Nginx\n- Domain: `sayhi.ngxtm.site`\n\n### Required Files\n\nThis repository includes the following deployment files:\n\n- `Dockerfile`\n- `.dockerignore`\n- `nginx.conf`\n\n### Dokploy Setup Steps\n\n1. Create a new application in Dokploy.\n2. Connect the application to your GitHub repository.\n3. Select the branch you want to deploy.\n4. Choose `Dockerfile` as the build method.\n5. Use the repository root as the build context.\n6. Set the Dockerfile path to `./Dockerfile`.\n7. Set the internal application port to `80`.\n8. Attach the domain `sayhi.ngxtm.site`.\n9. Enable SSL / Let's Encrypt.\n10. Run the first deployment manually, then enable auto deploy if the result is stable.\n\n### DNS\n\nCreate an `A` record for `sayhi.ngxtm.site` that points to your VPS public IP.\n\nIf you use Cloudflare, it is usually safer to start in DNS-only mode for the initial verification, then enable proxying later if needed.\n\n### Important Production Notes\n\n- Camera access requires `HTTPS` in production. If the site is served over plain HTTP, most browsers will block webcam access.\n- The app loads MediaPipe runtime and model assets from external URLs.\n- Client browsers must be able to access:\n  - `https://cdn.jsdelivr.net`\n  - `https://storage.googleapis.com`\n\n### Post-Deploy Checklist\n\nAfter deployment, verify the following on `https://sayhi.ngxtm.site`:\n\n1. The page loads without missing CSS or JavaScript files.\n2. The browser prompts for camera access.\n3. MediaPipe initializes successfully.\n4. Hand detection works in real time.\n5. Freeze, delayed capture, preview, and download all work as expected.\n6. The browser console does not show mixed-content, asset loading, or camera permission errors.\n\n## Available Scripts\n\nDefined in `package.json`:\n\n- `npm run dev`: starts the Vite development server\n- `npm run build`: runs TypeScript checks and creates a production build with Vite\n- `npm run preview`: serves the production build locally for verification\n\n## Usage\n\n1. Open the app in a supported browser.\n2. Allow camera access.\n3. Move your hand into view.\n4. Open your palm and hold the framing gesture steady for about one second.\n5. Wait for the app to freeze the scene.\n6. Choose a capture delay from the selector.\n7. Click the capture button.\n8. Review the preview image.\n9. Download the image if it looks correct.\n10. Use `Reset` to clear the frozen state and start over.\n\n## Project Structure\n\n```text\n.\n├─ index.html\n├─ package.json\n├─ package-lock.json\n├─ tsconfig.json\n├─ Dockerfile\n├─ nginx.conf\n├─ src/\n│  ├─ main.ts\n│  └─ style.css\n└─ README.md\n```\n\n## Implementation Notes\n\n- The application entry point is `src/main.ts`.\n- Styling lives in `src/style.css`.\n- The UI copy is currently written in Vietnamese, while this README is in English.\n- The app uses remote MediaPipe assets rather than bundling model files into the repository.\n- The capture flow is client-side only; there is no server upload or persistence layer.\n\n## Limitations\n\n- Camera permission is required. If access is denied, the app cannot initialize correctly.\n- Hand tracking quality depends on lighting, camera resolution, background clutter, and device performance.\n- Network restrictions can block MediaPipe runtime or model asset loading.\n- Browser support may vary, especially on older mobile devices or browsers with limited media capabilities.\n- The current repository does not include automated tests.\n\n## Troubleshooting\n\nIf the app does not start correctly:\n\n1. Confirm that your browser has permission to use the camera.\n2. Check that the webcam is not already locked by another application.\n3. Verify that your internet connection allows access to external MediaPipe asset URLs.\n4. Refresh the page after granting permissions.\n5. Re-run `npm install` if dependencies are missing.\n\nIf gesture tracking feels unstable:\n\n1. Use brighter and more even lighting.\n2. Keep your hand clearly visible and centered in frame.\n3. Reduce background clutter behind the hand.\n4. Try a device with a better camera or more GPU/CPU headroom.\n\n## License\n\nThis repository includes a `LICENSE` file. See that file for the applicable license terms.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fngxtm%2Fsay-hi","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fngxtm%2Fsay-hi","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fngxtm%2Fsay-hi/lists"}