Easy-to-manage touch screens
무료 오픈소스 터치스크린으로 USB 설정 가이드, 드래그‑드롭 편집기, 로컬 제어를 제공하며 Home Assistant용으로 제작되었습니다
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기A display case for a science fiction paperback collection, read by its spines
README 전체를 불러오는 중입니다.
README 전문 보기 ↗A shelf read by its spines
Vitrina stands a collection of Spanish-language science fiction paperbacks on a shelf built from their real spine scans. Each book is rendered at the height its catalogue record gives in centimetres, and the width comes from the scan's own aspect ratio, so a row comes out as uneven as the shelf it was photographed from. Click a spine and the book turns around: cover, imprint, translator, cover artist, table of contents.
It exists because the covers of the Ediciones B lines of the late 1980s and 1990s are hard to find anywhere else. La Tercera Fundación scanned them, and this is a way to stand in front of them.
Live: vitrina.neorgon.com
/demo/ shows a real collection
read-only, so the finished thing is visible before you start your own at
/shelf/, which begins empty/u/?handle -- reserve your shelf's address from Share
now. Publishing opens later, and until then nobody else can see any shelf. A
published shelf shows its address, its catalogue books and your shelf labels,
never notes, dates or books added by hand| Key | Does |
|---|---|
1 2 3 | Shelf, Covers, Browse |
/ | Focus the search box |
a | Add a book |
← → | Walk along the row with a book open |
Esc | Close the drawer or dialog |
La Tercera Fundación is a volunteer catalogue of Spanish-language science
fiction, and it has no public API, so scripts/scrape.py reads it: one request
every 1.2 seconds, a descriptive User-Agent, and an on-disk cache so a re-run
costs nothing. robots.txt allows crawlers in general and disallows ClaudeBot,
so the owner runs it and a Claude session never does.
Images are hotlinked, apart from small thumbnails of the shelf's own books.
The catalogue serves them from Cloudflare with a one-year cache header and no
hotlink protection, so the only cover art in this repo is assets/thumbs/,
described below. Otherwise it carries bibliographic facts only: titles, authors,
imprints, ISBNs, formats, page counts, tables of contents. Back cover copy is
deliberately not stored; the drawer links to the record instead.
python3 scripts/scrape.py resolve # my list -> candidate editions
python3 scripts/scrape.py detail # picked editions -> data/library.json
python3 scripts/scrape.py catalog # the collections my books live in
python3 scripts/scrape.py spines # which editions have a scanned spine
python3 scripts/scrape.py cache-images # local fallback copies
python3 scripts/scrape.py cache-images --catalog # ...for every browsable record
python3 scripts/thumbs.py # WebP thumbnails of your own books
Your own books are served from assets/thumbs/, sized to what the page paints:
the shelf's 31 spines drop from 218 KB to 84 KB and its 39 covers from 1.4 MB
to 563 KB. Everything else is asked of the catalogue, which is most of what the
whole-collection view draws and is why this repo carries a copy of what is on
the page and nothing more. If a request fails the shelf tries the catalogue,
then the gitignored data/images/ cache, then gives up and draws a spine.
scripts/rank.py scores the candidates for each wanted title and writes one
brief per book, which is what makes choosing between four editions of the same
novel a reading job rather than a guessing one.
ES modules require an HTTP server (not file://):
make serve # http://localhost:8881
make validate # every test, plain node and python, no install
make routes # regenerate /shelf/, /demo/ and /u/ from _templates/app.html
make validate needs a Node that strips TypeScript types by default (verified on v25.4.0).
The backend tests import convex/lib/*.ts directly, and a Node without that stops at the
first of those imports.
A signed-in person's shelf is kept in Convex, in the vitrina-site project, one
row per book under their Clerk account id; no email or name is stored. A
catalogue book's row holds its catalogue id and what the person wrote about
their copy: a shelf label, a note, the name they list it under and the date they
added it. The bibliographic record is read from data/ in the browser, so
nothing from the catalogue is copied per person. A book added by hand also keeps
a short record (title, authors, year, pages, publisher, collection, dimensions,
https: image URLs). Beyond the books an account has an optional handle, a
published switch, a running count of its books and bytes (at most 2000 books and
8 MiB), and rate-limit records, swept once they are 31 days old. Erasing an
account deletes all of it except a suspension, and holds the handle for 30 days.
Signing in is the fleet's Neorgon Auth Kit, on the one production Clerk instance
every Neorgon site shares. A visitor with no Neorgon session downloads neither
clerk-js nor the Convex client on /shelf/ or /demo/; /u/ loads the client
to read a shared shelf. The shelf kept in a browser never moves to an account on
its own.
Publishing ships closed: until the owner sets PUBLISHING to open on the
production deployment, no shelf is public, whatever its switch says. A published
shelf shows the handle, its catalogue books and their shelf labels, never notes,
dates or books added by hand.
make install # npm install, for the Convex CLI only; the site itself needs none
make where # which deployment the pages name, and which one .env.local pushes to
make push-dev # push convex/ to the dev deployment once
make deploy # deploy convex/ to production; it asks for confirmation
The functions in convex/ are thin wrappers over convex/lib/, which
make validate tests against an in-memory database. scripts/convex_smoke.py
calls the deployed ones end to end, on dev or on production.
vitrina-site/
├── index.html # the home page, which loads no app code
├── _templates/
│ └── app.html # app shell: controls, three views, drawer, dialogs
├── shelf/ demo/ u/ # the three app pages, generated by make routes
├── css/
│ ├── style.css # site styles; tokens come from the CDN base.css
│ └── neorgon-*.css # vendored with the header, footer, beacon and auth kits
├── js/
│ ├── app.js # entry point: loads, renders, then hands over to account.js or profile.js
│ ├── state.js # the shelf, prefs and which shelf is shown; the only module that writes the shelf
│ ├── syncplan.js # pure: between a browser shelf and an account shelf
│ ├── backend.js # the deployment a page names, every Convex function name, the loaders
│ ├── account.js # /shelf/: whose shelf is shown, and every write to the account
│ ├── session.js # what account.js shares with the modules that cannot import it
│ ├── strips.js # the notices above /shelf/, and moving a browser shelf into an account
│ ├── profile.js # /u/: a shared shelf, and its owner's own view of it
│ ├── share.js # the Share dialog: address, publishing, deleting your data
│ ├── accountplan.js # pure: what account.js, strips.js and share.js decide, and authedCall
│ ├── profileplan.js # pure: what /u/ decides: its states, which reply stays, the owner banner
│ ├── erasing.js # the timer the shelf and the Share dialog wait out a deletion with
│ ├── keyguard.js # pure: which keys the page leaves to a dialog or menu it does not own
│ ├── overflow.js # hides the header kit's ⋯ toggle while nothing in it is drawn
│ ├── handles.js # handle rules, mirrored from convex/lib/handles.ts
│ ├── data.js # loading, grouping, ordering, series gaps, the remote-image switch
│ ├── shelf.js # spine geometry: cm to pixels, aspect to width
│ ├── render.js # the three views
│ ├── detail.js # the drawer for one book
│ ├── browse.js # the catalogue, with owned books marked
│ ├── modals.js # add, import, export, shelf report
│ ├── events.js # most listeners, the keyboard and the Shelf tools menu; no inline onclick
│ ├── utils.js # folding, parsing cm and years, toast, download
│ └── neorgon-*.js # vendored kits, the Auth Kit among them; never edited here
├── convex/
│ ├── schema.ts # profiles, entries, shelfMeta, heldHandles, erasures, suspendedSubjects, rateEvents
│ ├── shelf.ts # shelf:mine and the three shelf writes
│ ├── profiles.ts # handles, publishing, byHandle, deleteMyData
│ ├── admin.ts # moderation, for ADMIN_SUBJECTS only
│ ├── purge.ts # erasure in batches, and the daily sweeps crons.ts runs
│ ├── http.ts # the Clerk user.deleted webhook
│ └── lib/ # every rule, as cores make validate imports with no install
├── tests/ # every one runs under make validate, with no install
│ └── support/
│ ├── fakedb.mjs # an in-memory Convex database for the convex/lib tests
│ ├── minidom.mjs # a small DOM the flow tests load a generated page into
│ └── shelfworld.mjs # a Convex deployment, a client and the Auth Kit, faked for the flow tests
├── scripts/
│ ├── tf.py # parser for tercerafundacion.net, no network in it
│ ├── scrape.py # the polite, cached client and its five modes
│ ├── rank.py # scores candidate editions, writes per-book briefs
│ ├── routes.py # writes /shelf/, /demo/ and /u/ from the template
│ ├── catalog_ids.py # keeps catalogue ids append-only
│ └── convex_smoke.py # calls the deployed functions on dev or production
└── data/
├── wantlist.json # what I own, by hand
├── candidates.json # every catalogued edition of each wanted title
├── picks.json # which edition, and why
├── library.json # the shelf: 39 books, full records
├── catalog.json # 774 browsable records across 5 collections
└── spines.json # which editions have a scanned spine