Easy-to-manage touch screens
무료 오픈소스 터치스크린으로 USB 설정 가이드, 드래그‑드롭 편집기, 로컬 제어를 제공하며 Home Assistant용으로 제작되었습니다
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기Navigate multi-day festivals with friends. Interactive schedule grid lets everyone mark their picks and spot overlaps.
저장소 README에서 가져옴
README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
A fast, mobile-first PWA for planning your festivals with your people. Add
your fests, add each fest's circle of friends, share one link per group — and
everyone's picks sync live, whether the lineup just dropped or the set times
are already out. Works offline once loaded, because the place you actually
need it is a field with one bar of signal.
Festivals loaded: 10 — the list lives in
data/festivals/index.json, which is the only place
it lives. Adding one: docs/add-a-festival.md.README 전문 보기 ↗Plan a festival with your friends. One link per crew, everyone's picks on one wall, live, and it still works in a field with one bar of signal.
Try it: fest.kevinhg.com
Live: v116, checked 2026-10-19.
The 2026 season is over (Portola in September, ACL in October). Still in the catalog, with crews already picking: EDC Orlando (Nov 6–8) and Seismic (Nov 13–15), both lineups waiting on set times, and Tomorrowland Winter (March 2027). This is a personal project built by Kevin HG for his friends, in the open.
Festivals loaded: 10. The list lives in
data/festivals/index.json, and only there.
Adding one: docs/add-a-festival.md.
− and + in its bottom corners, and the crew's notes.
Levels go picked ×1 → ×2 → ×3 → must; + climbs and − steps back.
With a mouse, hover grows the card and a click cycles the levels. Everyone
in the crew gets a color, and overlapping picks blend on the card, so you
can see at a glance where the crew is heading.js/errlog.js. Each carries
your name in the crew, your phone type and what you tapped, which
festival you had open, your public person id, a random id for the phone,
and its screen size and app build, all from an allowlist of fields and
words. Never note text, artist names or crew links; links and tokens are
scrubbed out of error messages.? or
# cut off (so never a crew link), plus the rough location, browser and
device type Vercel works out itself. No cookie, and no IP is kept with
the count.docs/fork-setup.md).Use Node 24, as CI does (package.json pins engines.node to 24.x).
The test tools ask for 24.15.0 or newer on that line (jsdom's own
engines); Node 22.22.2 or newer also runs everything, and there npm ci
prints an EBADENGINE warning about the 24.x pin, which is expected. No
build step: the CSS is hand-written and the JS ships as ES modules.
npm cinpm test runs the unit suite on a pinned clock. It needs no database
and no secrets: it runs the real merge SQL in-process (PGlite).npx playwright install chromium webkit once, then
npm run test:browser for the real-input contracts in Chromium and
WebKit.tests/README.md explains the pinned clock.
To run the app itself, npx vercel dev (the Vercel CLI is not one of this
repo's dependencies; install it globally if you'd rather type
vercel dev). Two traps, both real: it does not serve files created after
it started (restart it), and it pulls the real cloud environment, so
localhost talks to whatever database DATABASE_URL names. Point Development at a database branch, or treat local writes as
production writes.
Before your first deploy, point the app at yourself in three things:
index.html's fn-canonical-host tag (left as is, Spotify sign-in sends
your users' crew links to the upstream domain), its fn-report-key tag
(your own PostHog key, or empty), and the link-preview origin (ORIGIN in
api/share.js and the og:url and og:image tags in index.html; left
as is, every pasted link unfurls from the upstream domain).
docs/fork-setup.md has the exact steps in the order
that keeps the tests green, and the traps a real fork hit.
Deploy to Vercel (static files and functions).
Create a Postgres database (the free Neon tier is plenty) and load
the schema: psql "$DATABASE_URL" -f db/schema.sql
Set environment variables:
| Variable | Required | What it does |
|---|---|---|
DATABASE_URL | yes | the crew store |
GEMINI_API_KEY | no | AI festival research (api/festival-add.js) and the schedule-image import (api/import-schedule.js) |
GEMINI_MODEL | no | pins a Gemini model; default gemini-flash-latest |
OWNER_SPOTIFY_CLIENT_ID | no | your Spotify app, offered to your crew |
SLACK_WEBHOOK_URL | no | where Spotify access requests get sent |
APPROVE_SECRET | no | signs the approve link in that Slack message |
PUBLIC_BASE_URL | no | your origin, for that approve link |
The access-request flow turns on with the three Spotify and Slack
variables. On your own domain also set PUBLIC_BASE_URL: without it the
server trusts no host to build the approve link for, so no Slack message
is sent at all (the request is still recorded). Without the three
variables, members bring their own Spotify Client ID.
docs/add-a-festival.md is the format;
docs/fest-update-runbook.md brings one
festival's data up to date without losing anyone's picks. Two commands
matter:
node scripts/validate-festivals.mjs before committing (CI runs it too).node scripts/freeze-pick-keys.mjs <fest-id> the day real people start
picking. Artist names are pick keys, so a renamed artist would orphan
every pick on it; the freeze makes CI catch that.Ideas, bugs and pull requests are welcome:
CONTRIBUTING.md has the short version. Found a way to
read a crew you're not in? Please report it privately
(SECURITY.md).
Full paths, one per line. tests/docs-truth.test.mjs checks that every one
still exists, so this list can't quietly rot.
index.html app shell: every screen lives here
gallery.html every card, wall and zoom state on one page; the browser tests run against it
service-worker.js offline shell; node scripts/sw-stamp.mjs after any cached-file change
js/v3/app.js boot, wiring, screen assembly, sheets
js/v3/wall.js the wall: the timetable where a grid is published, venue stacks everywhere else
js/v3/card-facts.js the card's facts: the zoom (hover, keyboard) and the notes shelf's card (a tap)
js/v3/events.js the events model: the days, the rooms a day holds, a room's stack in play order
js/v3/motion.js how this app moves: the shared motion constants
js/v3/settings.js settings and its drills (Spotify, export, bulk paste)
js/v3/notes.js notes on a festival, a date, a section on a date, or an artist
js/v3/import.js picks from a festival app's schedule images
js/v3/model.js the read model over a crew doc + festival data
js/v3/aura.js how a crew's picks blend into one card's color
js/v3/palette.js the 24-color member board
js/v3/router.js history-backed navigation
js/state.js crew doc + the pending-changes overlay
js/sync.js push / poll, retry, and the sync dot's one truth
js/crew.js tokens, the local crew registry, share links
js/merge.js the deep-merge the client and server agree on
js/errlog.js the only door out: crash reports and usage counts, allowlisted
js/overlap.js same-stage lane math
js/time.js parsing and flooring set times
js/name-rules.mjs name validation SHARED with the server
api/crew.js the crew store: create, read, atomic merge
api/person.js the me link: one person across crews (public pid, secret token)
api/access.js Spotify access requests (Slack approve flow)
api/festival-add.js AI lineup research: returns a candidate; saves it as the crew's own festival once confirmed
api/import-schedule.js reads a schedule image; returns only what is printed, stores nothing
api/share.js per-festival link previews: index.html with its OG tags swapped
api/_lib/ validation + guards shared by client and server
db/schema.sql Neon Postgres schema incl. the atomic jsonb_deep_merge()
assets/v3-tokens.css design tokens: look values up here, never invent them
assets/v3.css components; hand-written, no framework, no build step
assets/mark.svg the mark: one vector source for every icon and preview
assets/og/ pre-rendered link previews, one per festival
data/festivals/index.json the festival list (single source of truth)
data/venues/index.json the venue registry: each room's usual doors, close and set lengths, with sources
scripts/validate-festivals.mjs run before committing festival data; CI enforces it
scripts/guess-run-times.mjs a night's set-time guesses (club or concert) from the venue registry, as a reviewable diff
scripts/brand-assets.mjs npm run brand: regenerates the icons and every link preview
tests/ node --test suites (npm test); every test runs on a pinned clock (tests/README.md)
tests/browser/ real-input contracts in Chromium and WebKit (npm run test:browser)
docs/user-flows.md what every screen is supposed to do
docs/add-a-festival.md how to add a festival
docs/fest-update-runbook.md bringing one festival's data up to date without orphaning a pick
docs/fork-setup.md forking and self-hosting, and the traps a real fork hit
AGENTS.md the rules of the repo, for people and coding agents alike
DEVLOG.md the story so far, newest first
claude-plans/ specs, build logs and reviews (claude-plans/README.md is the index)
Every pick is saved on the phone at once, then the change is pushed to
/api/crew, where Postgres merges it into the crew document in a single
atomic UPDATE through jsonb_deep_merge() (see
db/schema.sql). Because the merge is computed inside the
UPDATE, a second write waits on the row lock and then merges against the
first one's committed row, so two writes can't race by construction.
Other phones poll the merged doc every 25 seconds and again when the app
comes back to the screen. In Low power, or with the phone's Reduce Motion
on (it rides the same switch), the poll stretches to every 5 minutes and
coming back does not jump the queue. Removals sync as tombstones
(removed: true, and level-0 picks) because a deep merge can't express
deletion.
Two consequences worth knowing before you change anything here:
jsonb_deep_merge
replaces arrays wholesale, so an array would eat notes written at the same
time.Spotify's February 2026 rules shape this whole feature: a development-mode app is capped at 5 authorized users, a developer may hold one development-mode app, and the app's owner needs Premium.
So the app offers three doors, in the order most people will use them:
No open license. The code is public to read and learn from, and all rights
are reserved ("license": "UNLICENSED" in package.json); if you'd like to
reuse part of it, ask. The bundled vendor/html2canvas.min.js and
vendor/uqr.mjs keep their own MIT licenses (their headers are kept), and
the Anton and Inter fonts are under the SIL Open Font License.