BikeControl (SwiftControl)
Use Zwift Click, Zwift Play, Shimano Di2, or any Bluetooth controller with MyWhoosh, Rouvy, Zwift, and more. Free to try on iOS, Android, Windows, and macOS.
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
See every swimmer's best times on one page, straight from Hy-Tek meet results.
Load .cl2 result files from as many meets as you like, pick your swimmers, and
get a best-times table you can click through, print or export.
Private by design: everything happens in your browser. Result files are
never uploaded, and nothing about your swimmers leaves your computer.
Try the live demo » with a made-up team: tap any time to see
every swim.
Meet results contain children's names, ages and times, so the app is built to
keep them on your device:README 전문 보기 ↗See every swimmer's best times on one page, straight from Hy-Tek meet results.
Load .cl2 result files from as many meets as you like, pick your swimmers, and
get a best-times table you can click through, print or export.
Private by design: everything happens in your browser. Result files are never uploaded, and nothing about your swimmers leaves your computer.
Try the live demo » with a made-up team: tap any time to see every swim.
Meet results contain children's names, ages and times, so the app is built to keep them on your device:
connect-src 'none') and
from loading code, fonts or styles from anywhere but its own files. Even a
future bug or added script couldn't quietly send data out.If you use a hosted copy of the app (for example on GitHub Pages), the host only serves the app's own files. Your result files are still read in your browser and never reach the host.
Use it online at https://swimtimescoach.com. Nothing to install, and your files are still read only in your browser.
Or download the app as one file: swimtimescoach.com/swimtimescoach.html (about 270 KB, also linked in the app's footer). Double-click it and it opens in your browser with everything built in: it works offline, needs no install, and keeps the same privacy protections. It doesn't update itself, so download it again now and then for new features.
Getting entries ready for a meet? The SD3 course converter
fixes SCM/LCM seed courses in a TeamUnify .sd3 file (see
below). It's linked at the top of the app and in
Help & privacy.
Want to try it first? Download the five .cl2 files in
docs/sample-data/ (a made-up team, safe to share) and
add them to the app.
To work on the code, open index.html in a browser or start a local server:
npm run serve # http://localhost:8000, reachable from this computer only
The same guide is in the app under Help & privacy.
.cl2 files: Hy-Tek's results export, usually from
the meet host or results site. .sd3 files and .zip results
archives work too.If the files hold results from more than one team (a whole meet's results, say), the app asks Which team is yours? and from then on shows only your team's swimmers and the swims they did for your team. To switch, open the meet line above the table ("Sharks · 5 meets · …") and tap Change team. Saved sessions remember the choice; shared files only ever contain your team.
Choose swimmers lists everyone in the loaded meets. Search by name or filter by team, then Show table. With 15 swimmers or fewer, everyone is selected automatically.
Each cell is a swimmer's best time in that event. "3 swims" under a time means there are more: click the time to see every swim in that event, with the best marked. Only swims with a time are shown: scratches (SCR), no-shows (NS), DQs and DNFs are left out everywhere, including the swim counts, reports and exports.
Two views, switched with Columns above the table:
| View | Layout |
|---|---|
| By course | Each course gets its own columns: short course yards, short course meters, long course meters. |
| By event (SC + LC) | One column per event. Each cell stacks the short-course best over the long-course best, with Hy-Tek's course letters: Y yards, S short course meters, L long course meters, e.g. 35.31S over 34.06L. —SC or —LC means no swim in that course; a blank cell means no swims at all. |
By course: each course in its own block of columns.
By event (SC + LC): short course over long course in one column per event, shown here with EFSL quals on (boxes = qualified, underlined numbers = time still to drop).
Click either screenshot to open the live demo and try it. Both use the
made-up sample team in docs/sample-data/.
EFSL quals (checkbox on the Columns line) boxes the times that meet the
European Forces Swim League 2025–2028 championship standards: solid for Long
Distance Champs, dashed for Short Distance Champs. Each swimmer is judged at
their age on the championship's first day (Long Distance 27 Nov 2026,
Short Distance 27 Feb 2027; the dates can be changed in the EFSL reports
window), worked out from the birth date in their USS ID, and shown under each
swimmer's name ("13 at champs", or "12 at LD · 13 at SD" across a birthday).
Newer USS IDs don't contain a birth date: those swimmers get an amber
age 12? · no birth date label (in the table, the legend count and the
report) and are judged at their latest age in the results. Tap the label, or
use the list in the EFSL reports window, to enter their birth date: it's
checked against the ages printed in the results and kept in your saved session.
Birth dates are only used to work out ages:
they're never shown or exported, and shared files replace the IDs with
stand-ins and carry each swimmer's age at the championships instead. Times that don't qualify yet
show how much they still need to drop (e.g. −0.84), underlined solid or dashed
for the championship whose standard it is, in the table, the swim history,
prints and shared files. Every swim is judged at the swimmer's age at the
championship (see above), so a time that met the 12-year-old standard doesn't
count if the swimmer will be 13 by the championship, unless it also meets the
13 standard; a time equal to the standard counts. Only SCM and LCM (EFSL has no yards standards). The
boxes print, and shared files keep them, legend included.
EFSL reports… (next to EFSL quals) opens two reports for the selected swimmers, each with one section per championship and printable on its own:
Yards and meters times are never compared, so each course keeps its own best. 500/1000/1650 yards free share a column with 400/800/1500 meters, and the header lists only the distances actually swum ("400 Free" for a meters-only team, "400/500 Free" when both appear).
.zip with every loaded meet, the swimmers
you picked and the current view. Reopen it later with Open session (or
drop it on the page) to pick up where you left off. It's an ordinary zip:
unzip it to get the original .cl2 files back..html file with just the swimmers you picked,
to send by WhatsApp or email. The receiver taps it and the table opens in
their browser: no website, no upload, fully interactive. It contains only
those swimmers' individual results (no relays, splits or other swimmers).
Where a phone only shows a preview without running scripts, the file still
shows the best-times table and every swim; for the interactive version,
open swimtimescoach.com, tap Open session and choose the file. Expect
about 1 MB for a 70-swimmer team, under 300 KB for one swimmer.swimtimescoach.com/converter.html
fixes course codes in a TeamUnify .sd3 entries file or a Hy-Tek .cl2
results file, for example when SCM best times are submitted as seeds for a
long course meet. Like the app, it runs entirely in your browser. Open it from
the link at the top of the app, from Help & privacy, or from the footer.
It's a page of the website only, not part of the downloadable one-file app.
.sd3 or .cl2 file (unzip TeamUnify's .sd3_ext.zip first).Plain HTML, CSS and JavaScript: no build step, no framework, no runtime
dependencies. Third-party code and fonts are vendored in vendor/.
npm test # all tests, Node 18+, no dependencies
python3 tests/gen_fixtures.py # regenerate synthetic fixtures
npm run serve # local server on 127.0.0.1:8000
npm run build-share # build src/share-template.js ("Share as file"), swimtimescoach.html (downloadable app), demo.html
Every push to main runs the tests and, if they pass, publishes index.html,
converter.html, src/ and vendor/ to GitHub Pages (.github/workflows/pages.yml), after
building the app as one self-contained page: src/share-template.js (that
page as a string, for Share as file) and swimtimescoach.html (the same
page with no data: the downloadable app, which copies its own page to share
from), plus demo.html (that page loaded with the sample team). All are
generated and git-ignored; the website can't assemble them
itself because its CSP stops it from reading its own files at run time. The shared page
has its own CSP: only its exact inline scripts (by SHA-256 hash), embedded
fonts, no network.
Privacy rules for changes: keep the Content Security Policy in index.html
as strict as it is (in particular connect-src 'none'), load nothing from
other sites, and don't store result data in the browser.
| Path | What it is |
|---|---|
index.html | Page markup, Content Security Policy, in-app help |
src/cl2.js | SDIF v3 / CL2 parser, plus swimmer matching, best times and meet labels (browser global CL2, or require in Node) |
src/app.js | UI: file loading, swimmer picker, grid, detail dialog, print, CSV, sessions |
src/session.js | Save/open a session .zip (meet files + session.json) |
src/styles.css | Styles, including light/dark theme and print layout |
converter.html, src/converter.js, src/converter.css | SD3 course converter page (DOM and styles) |
src/sd3convert.js | SD3 course converter logic: parsing time fields, standard and custom conversion, the coach review report and its CSV, rebuilding the file byte for byte (browser global SD3Convert, or require in Node) |
vendor/jszip.min.js | JSZip 3.10.1, for reading .zip files |
vendor/fonts/ | Barlow and Barlow Condensed (latin, SIL OFL) |
tests/ | Node tests and synthetic fixtures |
tools/anonymize.js | Turns real .cl2 files into anonymized local test fixtures |
standards/efsl-2025-2028.json | EFSL championship qualification times 2025–2028 (Long and Short Distance Champs, SCM and LCM), for an upcoming "qualifying times" feature |
tools/make_efsl_standards.py | Builds that file from the times as printed in EFSL's PDF, checking each row against the table layout |
tools/make_sample_data.py | Generates the made-up sample meets in docs/sample-data/ (demo, README screenshots, try-it files): times built from the EFSL standards so the team shows qualifiers, near misses and far-off times |
docs/images/ | README screenshots |
tools/build-share.js | Builds the one-file app: the template and the downloadable |
MIT, Copyright (c) 2026 Panteley Matanov: free to use, copy, change and share, including commercially, as long as the copyright notice comes along.
Bundled third-party code and fonts keep their own licenses:
| Component | License |
|---|---|
JSZip 3.10.1 (vendor/jszip.min.js) | MIT (or GPLv3), notice kept in the file |
Barlow fonts (vendor/fonts/) | SIL Open Font License 1.1, see vendor/fonts/OFL.txt |
The downloadable app and shared files carry the same notices in their <head>.
Real results contain children's names, birth dates and IDs, so they are anonymized locally first and never committed:
npm run anonymize -- ~/path/to/real-cl2-folder # one team in the files
npm run anonymize -- ~/path/to/folder --list-teams # several teams: see codes (run it yourself)
npm run anonymize -- ~/path/to/folder --our-team CODE # ...then pick yours
Swimmers get mixed movie-star names, our team becomes Chicken Cats, other
teams and meets get fake names, and USS IDs and birth dates are replaced. The
same swimmer gets the same fake name in every file and on every run, via a
mapping kept at ~/swim-private/cl2-mapping.json (--map to change; it must
be outside the repo, since it holds the real names). Output goes to the
git-ignored tests/fixtures-private/, where npm test picks it up. Before
writing anything, the script checks that no real name, ID, team or meet
appears in the output, and that the app parses every swim identically.
Relay and split records are dropped, since the app doesn't use them yet.
swimtimescoach.htmldocs/sdif-v3-notes.md | Record layouts the parser relies on |