Netnyahoo
Mac용 실질적인 Chromium으로, Arc 사이드바와 Dia 폴리시를 갖추고 계정 없이 무료·오픈소스이며 광고·추적·소송에 면역이다
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기메이커가 쓴 소개는 위의 한 줄이 전부입니다. 더 자세한 내용은 저장소 README에서 읽을 수 있습니다. 저장소 README ↗
README 전체를 불러오는 중입니다.
README 전문 보기 ↗A kiosk website for collecting student feedback with hand gestures. You keep a list of questions on the admin page and assign each one to one or more variants. The kiosk runs one variant at a time and asks that variant's questions in random order. Until someone waves at it, the kiosk shows an idle screen. There are three variants:
Hand tracking runs in the browser with MediaPipe Gesture Recognizer. Video never leaves the device. Only the answer is sent to the server.
Requires Node.js 22.13 or newer and Docker (OrbStack or Docker Desktop) for the Postgres database.
docker compose up -d
npm install
ADMIN_PASSWORD=choose-a-password npm start
If ADMIN_PASSWORD isn't set, the password is admin. Set a real one before using it with students.
Questions and answers are stored in Postgres 17, which docker-compose.yml runs on 127.0.0.1:5434 with its data in the pgdata Docker volume. The server creates its tables on start. Set DATABASE_URL to use another database (default postgres://feedback:feedback@localhost:5434/feedback).
questions: the text and the variants it is assigned to (variants, an array).answers: one row per answer, with the question, the variant it was given in, and answer (agree/disagree, thumbs) or rating (1–5, stars and fingers). Deleting a question deletes its answers.settings: the variant and camera the kiosk uses.To start over, run docker compose down -v, which also deletes the volume.
Earlier versions stored everything in data/feedback.db. To copy that into Postgres once:
npm run import-sqlite
Statements with the same text become one question, assigned to every variant they were asked in, and their votes and ratings become that question's answers with the original timestamps. The import only runs into an empty database and never changes the SQLite file. Set DB_PATH to import a different file.
WAVE_MAX_TILT), and a row of dots fills as it does. A swing must move the hand sideways at least 0.9 palm length (WAVE_SWING), so it works at any distance from the camera, and further sideways than up or down. It must take at least 0.1 seconds (WAVE_MIN_SWING_MS), so a jump in the tracking doesn't count, and the next swing must follow within 0.8 seconds (WAVE_GAP_MS). Three swings (WAVE_SWINGS), back, forth and back again, wake the kiosk: about a second of normal waving. Anything else, like raising the hand into view or moving it about, starts the count over. If no question is assigned to the active variant, the idle screen says so and ignores waves.
Which hand is followed. The model looks for up to three hands (MAX_HANDS), and the kiosk follows the raised one: the hand highest in the picture. A hand that points, waves or makes a gesture is held up, so a hand resting at the bottom of the picture never takes over. A new hand less than a third of the size of the biggest one (HAND_MIN_SIZE) belongs to someone further away and is ignored, but the hand being followed is kept whatever its size, for example when a resting hand is much closer to a laptop camera. Another hand only takes over when it is at least a palm higher than the followed hand (HAND_SWITCH), so two hands at about the same height don't flicker. A hand moving fast blurs and can be lost for a few frames: for 0.4 seconds (HAND_LOCK_MS) the kiosk keeps its square in place and waits for it, instead of jumping to a lower hand. A hand of about the same size that turns up at the same height or higher counts as the same hand, however far to the side, because a waving hand that blurs mid-swing comes back at the other end of the swing.IDLE_AFTER_MS), the kiosk goes back to the idle screen.MIN_SCORE), a large ring fills. If the student switches thumbs, it starts over. If they drop the gesture, it resets.Which question is shown. The kiosk asks the questions assigned to the active variant one at a time, in random order. Every question is asked once before any is repeated, and the same question never comes twice in a row. Questions added on the admin page join the current round. If no question is assigned to the active variant, the kiosk says so and doesn't accept answers. It checks for a new variant and for changed questions every few seconds (POLL_MS).
The timings, the star hit area, the cursor smoothing, the finger-count thresholds (FINGER_RATIO, THUMB_RATIO) and the wave detection are defined at the top of public/kiosk.js. Each variant has its own hold time: THUMBS_HOLD_MS (3 s), STARS_HOLD_MS (1 s) and FINGERS_HOLD_MS (3 s).
Variants are thumbs, stars and fingers.
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /api/kiosk | – | {variant, camera, questions: [{id, text}]}: the kiosk settings and the questions assigned to the active variant |
| POST | /api/answers | – | {questionId, variant, answer: "agree" | "disagree"} for thumbs, or {questionId, variant, rating: 1–5} for stars and fingers. Returns the question's updated results for that variant |
| GET | /api/settings | – | {variant, camera}: the variant and camera the kiosk uses. camera is macbook or logitech |
| PATCH | /api/settings | admin | {variant?, camera?} changes either or both |
| GET | /api/questions | admin | All questions, newest first, each with results per variant |
| POST | /api/questions | admin | {text, variants} adds a question |
| PATCH | /api/questions/:id | admin | {text?, variants?} changes a question |
| DELETE | /api/questions/:id | admin | Deletes a question and its answers |
| GET | /api/questions/:id/answers | admin | Every answer to a question, newest first |
| GET | /api/export.csv | admin | All answers as CSV |
Admin requests send the password in the x-admin-password header.
You pick the camera on the admin page. The kiosk switches within a few seconds, without a reload. Each camera is defined in CAMERAS at the top of public/kiosk.js:
| Camera | Found by name | Picture |
|---|---|---|
| MacBook camera | "FaceTime", "MacBook" or "Built-in" | Landscape (up to 1920×1080), as the sensor delivers it. For testing on a laptop. |
| Logitech StreamCam | "StreamCam", then "Logitech" | Portrait 1080×1920 for the vertical display. Mount the camera upright: the kiosk rotates its picture 270°. |
The picture is always mirrored, so it feels like a mirror. If the chosen camera isn't connected, the kiosk uses the browser's default camera and logs a warning in the console. To correct the orientation of a camera, change its rotation (clockwise, in degrees).
Browsers only allow camera access on localhost or HTTPS. Running the server and kiosk on the same machine works as is. If the kiosk runs on a different device, such as a tablet, serve the site over HTTPS, for example:
DATABASE_URL.npx localtunnel --port 3000, or use cloudflared tunnel --url http://localhost:3000.--kiosk flag also works.STABLE_FRAMES), and changing the count restarts the timer. A fist (0 fingers) isn't an answer.