Boardsesh
Kilter·Tension·MoonBoard와 연동해 세션 추적·LED 제어·함께 등반
UCG WAG, MAG, T&T 루틴을 계획하고 시작값을 계산해 완성된 UCG 워크시트와 대회 카드를 내보냅니다
Plan UCG WAG, MAG and T&T routines, calculate start values, and export filled-in UCG worksheets and competition cards.
스포츠·피트니스JavaScript · CSSGitHub @United-Club-Gymnastics온라인운영자 미확인
써 보셨어요? 한 번만 눌러 주세요. 로그인은 필요 없어요.
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기UCG Routine Planner: plan WAG, MAG and T&T routines and start values
저장소 README에서 가져옴
README 전체를 불러오는 중입니다.
README 전문 보기 ↗One planner for every UCG discipline and level: WAG (Xcel Silver, Gold, Platinum, Diamond, Sapphire, UCG Infinity, Masters), MAG (Developmental, Intermediate, Advanced, Masters) and T&T (New, Intermediate and High Flyers). Gymnasts and coaches sign in with Google (or try it without signing in, which saves nothing), add athletes, add the levels each athlete competes, build routines, and export filled-in UCG worksheets and competition cards.
Live site: https://routines.unitedclubgymnastics.org/ (custom domain on GitHub Pages: a CNAME for routines in the WordPress.com DNS for unitedclubgymnastics.org; the old united-club-gymnastics.github.io/ucg-routine-planner/ address redirects there. The domain is also in Firebase Authentication → Authorized domains.)
Grew out of the MAG planner (ucg-mag-planner) and Julia Sharpe's UCG Infinity SV Sheets; both are still live and unchanged.
| Piece | Where | Who can change it |
|---|---|---|
| Code and hosting | This repo in the United-Club-Gymnastics GitHub organization, published by GitHub Pages | Organization owners and members with write access |
| Sign-in and saved routines | Firebase project ucg-routine-planners, in the unitedclubgymnastics.org Google Cloud organization | Everyone in [email protected] |
| Rules | UCG rules policies for each discipline | Each discipline's rules team |
Athletes are saved in Firestore at users/{user id}/athletes/{athlete}. Each athlete holds a list of entries, one per level they compete ({ disc, level, decade?, routines, passes, options, vault }). The MAG planner's data (magAthletes) is separate and untouched. Guests who haven't signed in are kept in memory only; if they sign in, their athletes are saved to their account.
Saved data is never dropped on load (js/athlete-doc.js). Each athlete carries schemaVersion (now 2), and migrateAthlete brings older shapes up to date in memory; nothing is written until the coach's next edit. An entry with a discipline or level this version doesn't know is kept aside, hidden (the editor says so), and saved back unchanged; an athlete saved by a newer schemaVersion is shown but not saved over. A saved vault the level no longer offers keeps its ID and is flagged instead of showing an empty box. Saved rows keep their values, so when the Code changes a listed skill's value or group, the row shows Value changed and the event offers Update values (valueChange in js/model.js); entries whose values came from the skill lists carry catalog (the skill bundle's commit, set by the build). Fixtures of old shapes: tests/fixtures/athletes/.
| File | What it does |
|---|---|
js/model.js | Disciplines, levels and events; one scoreEvent / scoreEntry for every level; copying routines between levels |
js/scoring/mag.js | MAG Dev / Int / Adv / Masters |
js/scoring/wag.js | UCG Infinity, Xcel, WAG Masters |
js/scoring/masters.js | Masters age-decade values and vault age bonus (shared by MAG and WAG) |
js/scoring/tt.js | T&T difficulty totals and level requirement checks |
js/data/ | Skill lists, vault tables, Xcel requirements, example routines (most generated, see below) |
js/app.js | The screen: athlete search, levels, routines, skill picker |
js/pdf.js, js/pdf-infinity.js | PDF export |
The rules' sources of record are UCG's Google Docs and Sheets (Nate, 2026-10-20). Cite and check these, not PDF or Word copies, which go out of date:
| Rules | Source of record |
|---|---|
| UCG Women's Rules (Xcel levels) | https://docs.google.com/document/d/1FuuEUaLWjk0NTADYSfr2RDprikdjxjcqEdrdHRmIAtg/edit |
| UCG Infinity (Open Scoring Level) Rules | https://docs.google.com/document/d/1Us_lv6CADGZSOZDHEWb5nHzq7Z5XhhIFFwyFnTWlbVA/edit |
| UCG MAG Rules Policy 2026-28 | https://docs.google.com/document/d/1hTJjtE5UNa6bj1nWi37LvoJ3coeobLuD2-TLoO066Us/edit |
| UCG MAG Rules Breakdown (level table) | https://docs.google.com/spreadsheets/d/13lx3jKzxjbMOovUb6ZZNI4FzzsVF6rApsPDvUjCnTps/edit#gid=1498227199 |
| UCG Masters Rules Policy | https://docs.google.com/document/d/1VeRTNv1KVrkCbHEo9r36qbRBxt0Me6VJ66E8jkvck_c/edit |
They open with the UCG account ([email protected]). gym-skill-extract's rules/UCG-*
holds dated text extracts and own-words digests of them (rules/gdoc_text.py refreshes the extracts).
MAG (2026-2028 UCG MAG Rules + MAG worksheets): see the MAG planner's README; unchanged here except that Masters is added, and that Advanced requirements and bonuses the routine itself shows are detected from the skill list: the floor double flip (any double or triple salto), the floor double flipping dismount (the last skill listed is a double or triple salto; every level), and the rings swing to handstand (I.75, I.81, I.86, I.87, I.88, per the WG clarification). Skills typed in by hand are matched by name for the floor doubles; otherwise the gymnast ticks the box. Counting (WG §6.1, MAG-NL-1): Intermediate and Advanced count the dismount first, then the 7 best (the dismount is the last skill: on floor the last one not from EG I, elsewhere an EG IV skill or one with no group); Developmental counts its 6 highest (Nate, 2026-10-20). WG newsletters at Advanced (Nate, 2026-10-20): floor −0.3 without a one-leg balance or a jump from the WG list (fxBalanceOrJump, may be outside the counting skills) and −0.3 if the routine doesn't start with a tumbling pass (an EG II-IV skill or a round-off, which has no EG); Pommel horse handstand elements (WG §11 2.c.4; Nate, 2026-11-02) are in the skill list at each value they can earn: a circle or flair handstand dismount one value higher with a 450°+ turn or a 3/3 travel (3/3 needs at least 270°), two with both; a handstand lowered to circles or flairs, with a 360°+ turn or a 3/3 travel (min. 180°). Each value is its own form (e.g. WG-PH-IV-20b, C), from the bundle's forms (gym-skill-extract WG MAG CoP Extraction/element_forms.json); form a keeps the bare ID. IV.4 and IV.5 are already the +2 forms of IV.20 and IV.15. At Masters, values above D count as D+; high bar counts at most two flights of each style (Tkatchev/Piatti, Kovacs with II.82/II.83, Gienger, Jäger, Markelov, front saltos over the bar: the planner's own table, tools/source/hb_flight_styles.json) and a 5th flight (EG II) when two flights are linked C + C or better. Not modelled: stick bonuses (live-routine only), the PB compositional deductions of MAG-NL-3 (judging only, Nate 2026-10-20). MAG Masters (UCG Masters Rules Policy v2.1, aligned with the international Masters CoP 2025-2028): values by age decade (GE, ME, A, B, C, D+; GE replaced "Misc." on 2026-10-20 and is worth 0.0/0.1/0.2 from 50; saved "Misc" rows read as GE); the dismount plus the best 6 others count (5 from 60), −1.0 per missing skill, and a routine without a dismount is one short; element group bonus +0.3 or +0.5 by the skill's level and the decade, no limit per group, but a group-filling skill counts instead of a higher one when that helps the score; dismount group worth the dismount's value up to 0.5 (floor has no dismount group); no rings strength-sequence rule; vault = WG or Masters CoP vault value + age bonus (the UCG MAG CoP's own vaults aren't offered at Masters). The tables come from the bundle's (), the WG MAG lists from (). flipping and round-off-entry vaults are banned (score 0); only the front and sideways handsprings without salto remain. skills are worth 0.0 but count toward the 6 skills.
UCG Infinity (UCG Infinity Rules v1.2; the +0.3 event bonuses are back in v1.2): A=0.1, B=0.3, C=0.5, D=0.7, E=0.9; top 8 count; +0.3 per condensed group with a B or higher (counting or not); +0.3 apparatus bonus; -1.0 per skill under 6 (a listed skill with no value, e.g. the no-value high cast offered at Sapphire and Infinity, shows in the routine but earns nothing and isn't one of the 6); vault from the Infinity vault table.
Xcel (UCG Women's Rules v6.0 + USAG Xcel Code 2022-2028 event charts): start 10.0 (Sapphire 9.6 + up to 0.4 bonus); -0.50 per missing special requirement; minus the value of each missing value part (A=0.1, B=0.3, C=0.5; a higher value part can fill a lower one); -0.50 per restricted skill (above the level's limit; Diamond allows one D; Sapphire has no restrictions, Ds and Es included; Platinum bars counts the clear hip, stalder and toe-on circle to handstand without turn as B). js/scoring/xcel-rules.js works out, from each listed skill's catalog tags (acro, flight, salto, 360° circle, ...; t in skill-index-wag.js) and the connections: restrictions by kind of skill (Silver "B" acro, Gold giants, ...); which special requirements the routine meets and by which skills, some "assuming" what a plan can't show (a cast's angle, a leap's split, which bar), which the coach can untick (or tick one met by a typed-in skill; stored as options[event].srSet, only where it differs from the detection); and the Sapphire bonus (+0.1 per "C" and one "D" or "E", +0.1 per "B"+"B" connection, floor indirect acro too; only skills in the Xcel Code and UCG's own WAG additions, except that a Development Program E can earn the one-"D" bonus, since an E counts as a D (Nate, 2026-10-20); 0.40 max). Vaults from the Xcel vault chart; Gold 9.5 with the alternative springboard; Sapphire also lists the USAG Level 9/10 vaults that aren't in its chart, at 10.0. Counting an element more than once (Xcel CoP General D-F and each event's Chapter 2): an element earns value-part credit at most twice, the second time only in a different connection (a different element before or after it); never a third time. Bars routines are treated as one continuous sequence for repeats, and a mount element done again inside the routine (a glide kip or long hang kip after the mount) is a different element from the mount (the first skill, when it is a Group 1 or mount-tagged skill, or a typed-in skill in group 1; bars §VII.B.2.e; Nate, 2026-10-30; also at UCG Infinity); on every event the gymnast marks directly connected skills with the link toggle between rows. On floor the connection that counts is the pass and the place in it, and acro flight elements with hand support (round-off, flic-flac, ...) earn credit every time in a different pass. Records the Code treats as several different elements are split into forms (from the extractor; one skill per form, e.g. USAG-BB-7.104-1b one-arm back walkover; the bare record id stays as an alias of form "a"), and same_as links division stand-ins to the regular skills. Which listed versions of one USAG number are the same element comes from a per-number review (the skill bundle's ; Nate ruled on its calls on 2026-10-19). UCG Infinity: each element earns credit once, whatever the connection. Xcel levels get the USAG Xcel skills (without ones limited to other divisions, e.g. "Bronze/Silver/Gold only") and the UCG additions; Sapphire and UCG Infinity (the Open Scoring Level) also get the USAG Development Program E elements; WAG Masters gets the WG skills. USAG skill names are our own short names, not the Code's text (see in ).
WAG Masters (policy v2.1): values by age decade; the dismount plus the best 6 others count (5 from 60), −1.0 per missing skill. Composition Requirements replace the condensed groups: CR I-IV +0.5 each for a skill of at least ME (GE from 50), counting or not; the dismount CR V +0.3 or +0.5 by its level and the decade; from 60, bars CR I and II give +0.3 even without the element. The planner detects them from its own tags (tools/source/masters_wag_tags.json, built into js/data/masters-wag-tags.js: WG skills by WG group and name, the Masters-only skills by hand) and the connected skills; the coach can tick or untick each (options[event].srSet, as for Xcel). Beam: the beam bonus (40s +0.5, 50s +0.8, 60s +1.2, 70+ +1.5) unless the gymnast uses a widening (options.bb.widening: none / offered / used; without a widening, Table 2's 60+ relaxations apply). The skill search offers the WG WAG skills and the Masters additions. Vault = the vault's value + age bonus, from the UCG Masters vaults (squat on, roll over, hechts, forward headspring, sideways handsprings) or the WG WAG vault table, or 0.0 for any other vault.
T&T (UCG T&T Code of Points v3.41 + DD charts; double mini tuck/pike/straddle jumps are 0.0, per the UCG addendum, until the T&T team decides on WG's change): total DD per routine or pass, with each level's requirements flagged (max skill DD, salto counts, pass and routine DD limits, repeats, pass sizes). Double mini: each pass's first skill is marked mounter or spotter (stored as start on the pass, default mounter), since a repeat only loses its difficulty in the same position. Saltos are recognised from the FIG shorthand, or the skill name when there's no shorthand.
The skill bundle's catalog/ (tools/source/bundle/catalog/, see "Skill bundle" below) holds the cross-code skill catalog built in the gym-skill-extract repo (only the *_public catalogs, aliases_*.json and levels.json; the full catalogs carry the codes' text and stay private). build_data.py turns it into:
js/data/skill-index.js: each planner skill's box number in its own code (WG I.75, Xcel 7.104, DP 1.512, UCG FX 12, Masters PB 12 with the page) and other names coaches use. Shown in the skill list and on the picked row; searchable.js/data/masters-skills.js: the UCG Masters MAG and WAG skill lists. MAG Masters offers WG + this list instead of the main UCG MAG additions; WAG Masters offers WG + this list.js/data/catalog-{wag,mag}.js: loaded only when a routine is copied to another level. js/revalue.js then gives each listed skill the target level's code entry (value, element group, planner skill), per levels.json: first code in value_codes with an entry; WG adjusted_value (beam jumps in side position) wins; approximate when the routine's own record is broader than the element or maps to several; not credited (kept, flagged, worth nothing) when no code of that level has it; skills typed in by hand are flagged to check. The entry records the catalog and levels versions it was re-valued with. Vaults are carried over the same way: the same vault in the target level's own list (Masters: WG or UCG Masters vaults; Xcel: that level's chart, plus Level 9/10 vaults at Sapphire; Infinity: its vault table, matched by USAG number), approximate when only a broader record matches; otherwise the level's rule (Masters: any other vault, 0.0 + age bonus; otherwise no vault, flagged). Masters values are "GE" (Gymnastics Element; "Misc" until 2026-10-20) and "ME".Routines store the planner's skill ids, which the catalog's aliases resolve (with merged), so catalog rebuilds don't break saved routines. To update: npm run sync-skills.
WAG catalog 06016336f87b, MAG catalog 416d8893cfa6 (2026-10-19, the first synced skill bundle): UCG MAG PB "Peach 1/2 to hang" (UCG and Masters, same IDs) is now "Felge (peach) ½ to hang", and its other names are "Felge (basket) ½ to hang" and "Felge (peach basket) ½ to hang". The retired Masters WAG straight hecht vault (UCGM-wag-straight-hecht-over-table, already gone from the Masters vault list since 2026-10-06) loses its catalog element entry and box label, so copying a routine that still holds it to another level gives "no vault, flagged". No other skill's name, value, element group or other names changed, and no skills were added or removed.
WAG catalog 65d08096cdae, MAG catalog 7aca10f8a5d5 (2026-10-18): the re-laid-out UCG WAG and Masters WAG Codes. Masters WAG gains 8 skills copied from the UCG WAG additions (UB straddle vault mount with ½ turn; BB handstand drop to shoulderstand (no hold), front lever, jump backward with ½ turn to chest stand, two and three scissors mounts, mount with 2 circles and a 360° russian; FX round-off from both feet), each in the same catalog element as its UCG WAG original. A new Masters page 5 (Balance Beam cont.) moves FX and UB (cont.) one page later, and 18 Masters boxes are renumbered (skill-index-wag.js shows the new numbers and pages). Masters eponyms now match UCG WAG (BB 21 and UCG BB 10 are "Lim/Niolet"). The MAG change is a video link only; build_skills.py also picks up the Code of Points' "Penn 1/Sharpe" spelling on the UCG HB toe-on. No planner IDs changed or were retired.
MAG catalog 1ddacb9a8d8b (2026-10-17): UCG MAG PB 16 (Backward roll to L with straight body) is retired into PB 15, now "Bwd. roll piked or stretched from upper arm to support" (MAG-PB-0193 forwards to MAG-PB-0192). Routines saved with the old UCG or Masters ID open on PB 15 (js/data/mag-redirects.js).
MAG catalog e403916a0bb1 (2026-10-16): the Code of Points repo's corrections: video links on UCG MAG records, Masters MAG notes that were missing, two PH drawing labels no longer read as eponyms, fuller Masters names ("... x2"), the two renamed UCG boxes (SR basket pull up to L, VT hecht backflip) under their new names with the same IDs, and the Masters "Russian + Flop combo" merged into the UCG addition (MAG-PH-0127 forwards to MAG-PH-0115, under merged in aliases_mag.json). No planner IDs changed.
Planner-side additions (2026-10-13), now in the skill catalog (4c6890300dcb): stand-ins so these copy to WAG Masters instead of "not credited": WAG-FX-0112 (Xcel split leap or split jump) gets WG FX 1.101 split leap and WAG-BB-0283 (full turn in arabesque) gets WG BB 3.302 full turn in back attitude, both with "relation": "stand_in" (re-valued as approximate); WAG-FX-0165 (handstand forward roll) gets the UCG Masters ME "Handstand (any entry, no hold) forward roll out", also a stand-in. The Dropbox catalog builds them from skill_catalog/matching/ucg_rulings.json (stand_ins).
Planner-side additions (2026-10-14, WAG rules lead's bars and beam feedback), now in the skill catalog (4c6890300dcb, now in the gym-skill-extract repo). The new records are in UCG WAG Skills/ucg_rulings.json; the catalog's same / covers / stand-in rulings and element names in skill_catalog/matching/ucg_rulings.json; tags in skill_catalog/tags/tags_manual.json; other names in skill_catalog/aka.json (2.301-4's Higgins names under records_only). Later changes to these go there, not to the copies here:
1.101 v3 Long hang kip, A (new element WAG-UB-0507, tags HB + kip); UB 2.001 v7 High cast, 21°+ off vertical (no value), value null, Sapphire only, so Sapphire and Infinity (WAG-UB-0508); UB 2.102 v2 Cast squat/stoop/straddle on, jump to HB, A (covers_more record in each of 2.102-1's elements, tags LB + bar change); UB 2.301 v4 Cast handstand, Higgins ½ turn to L grip, C (Xcel record added to WAG-UB-0382, the DP 2.301-3 element); BB 2.0 Gold and 2.0 Platinum v2 Straddle jump, 120°–135° and v3 Sissonne, 120°–135°, A, division stand-ins same_as 2.202-1 and 2.207-1 (WAG-BB-0542 to 0545).WAG-UB-0382 element would also reach 2.301-2, which maps there). "Long hang kip", "High bar kip" and "HB kip" move from 1.106 (both its listings, WAG-UB-0370 and 0371) to the new 1.101 long hang kip.wag_same_elements.json, repo only): 2.301-4 is the same element as 2.301-2 (grip only, as in 2.401), 2.102-2 as 2.102-1, 2.001-7 joins the 2.001 casts.| Data | Source | Rebuild |
|---|---|---|
data/mag-skills.js, data/mag-vaults.js, data/mag-redirects.js | Bundle skills/ucg-mag.json (UCG MAG CoP additions, code UCG-MAG-ADD, whose skill IDs are frozen in ucg-code-of-points; removed records left out) + skills/wg-mag.json (FIG MAG CoP 2025-2028). Redirects (retired ID -> the skill it was merged into) from ucg-mag.json and ucg-masters-mag.json. GymACT vault values (ADV_VAULT) and the no-salto vaults (NON_FLIPPING) come from bundle rules/UCG-MAG/digest/vault.json | python tools/build_skills.py |
data/wag-skills.js | Bundle skills/wg-wag.json (WG WAG CoP 2025-2028; tags.salto marks the saltos) + skills/ucg_wag_skills_simplified.json (USAG Xcel 2022-2028, USAG Development Program 2026-2030 E elements and the UCG WAG CoP additions, with our own short names for the USAG skills) | python tools/build_data.py |
data/wag-redirects.js | Redirects from bundle skills/ucg-wag.json and ucg-masters-wag.json (none yet); the WAG loader maps them as the MAG one does | python tools/build_data.py |
data/wag-same.js | Bundle rules/USAG-XCEL-2022/digest/same-element.json: which listed versions of a USAG number count as the same element, and the floor hand-support flight elements (reviewed against the Xcel and Development Program codes; reasons in our own words) | python tools/build_data.py |
data/sapphire-vaults.js | USAG Level 9/10 vaults not in the Xcel Sapphire chart (same simplified file) | python tools/build_data.py |
data/wag-vaults.js | WG WAG vault table (wg-wag.json) | python tools/build_data.py |
data/masters-vaults.js | Bundle skills/ucg-masters-vaults.json (owned by ucg-code-of-points): the vaults that aren't in the WG code (rows with a planner ID; retired IDs left out) and the vault age bonus per decade. The build also checks the table's WG rows against the WG values and stops on a mismatch |
tools/source/*_notes.md record the judgment calls made while extracting (e.g. the DMT jump values, strikethroughs on the DD charts).
All skill and rules data except T&T comes from the skill bundle that gym-skill-extract publishes (its bundle/, docs/ARCHITECTURE.md §4 there): the public skill files, the cross-code catalog, levels.json, the rules digest JSON and the schemas, with a manifest.json listing each file's sha256. It is vendored, unchanged, in tools/source/bundle/ and pinned by tools/source/bundle.lock.json, so the planner builds from its own checkout.
npm run sync-skills (python tools/sync_bundle.py; needs pip install jsonschema rfc3987 and the gym-skill-extract checkout, GYM_SKILL_EXTRACT_DIR, default C:/dev/gym-skill-extract, with its bundle/ committed). It copies the bundle, checks the file set and every sha256 against the manifest, each file against its schema, the schema major (0) and the catalog versions, writes the lock, runs both builders and prints the added, removed, renamed and revalued records and new redirects of the skill files, the Masters vault rows and age bonus that changed, and the catalogs' new merged entries. Then commit tools/source/bundle/, the lock and js/data/.npm run check-bundle (also a test and a CI step before the tests) fails if a vendored file differs from the manifest or the manifest from the lock (a hand edit), or if js/data/catalog-*.js wasn't rebuilt from the bundle's catalog. python tools/sync_bundle.py --check does the same plus the schemas.tools/source/bundle/. Fix the data where it's owned (gym-skill-extract, or ucg-code-of-points for UCG skills and Masters vaults), rebuild the bundle there, and sync.tools/source/published-ids.json lists every skill and vault ID this site has ever shipped (the keys of the bundle's aliases_*.json; seeded 2026-10-20 from the repo's history) and only ever grows. sync-skills refuses a bundle in which one of them is neither an alias, a redirect nor retired by ucg-code-of-points (a renamed record), check-bundle and tests/published-ids.test.mjs check the vendored bundle the same way, and the test also resolves every published skill ID through findSkill. A retired ID with no redirect is a deliberate CoP decision (cop.py remove --no-redirect): saved rows holding it show as "Custom".note_edits.json (our short skill notes), tt_skills.json and its notes (the T&T DD charts, not yet in gym-skill-extract), examples.json and its notes (routine examples aren't skill data), infinity_vault_ids.json (the Infinity vaults' permanent ids), and calibration_infinity.json (judge practice: see below).MAG Dev/Int/Adv and the T&T cards are the printouts people already fill in by hand; the planner writes onto them at fixed positions measured from each PDF (LAYOUTS in js/pdf.js). If a sheet changes, replace it in assets/worksheets/ and re-measure. UCG Infinity uses Julia's worksheet. Xcel uses a low-ink worksheet drawn in js/pdf.js (there's no official one), and MAG and WAG Masters a low-ink, UCG-branded drawing of the Masters WAG SV worksheet (2026 Individual World Cup) with its age-decade value table (the printed MAG Masters sheet, with 6 rows and "Misc.", was retired for policy v2.1).
https://routines.unitedclubgymnastics.org/calibration/infinity/ (calibration/infinity/): judges practise UCG Infinity difficulty on the calibration routine videos. Each routine's video (a Google Drive embed; portrait videos sit beside the calculator, landscape ones get a wide frame) is next to the judging calculator's difficulty inputs (A-E counts, element groups I-IV, apparatus bonus; vault from the Infinity vault chart). Deductions are shown but off: execution is judged as in Xcel Sapphire, and the page links to the real calculator. Did I get it right? compares the entry with the answer key, marks each input right or wrong, and says why (which skills make the count, which skill earns a group, why the apparatus bonus is or isn't earned); See the routine laid out shows every skill with its value, group and credit, and the start value sum, with Open in Routine Planner. Progress (right / tried) is kept in that browser only. A routine can be linked directly: …/calibration/infinity/#FX_4.
tools/source/calibration_infinity.json (what the sheet doesn't hold: skills outside the top 8 that earn something, why each apparatus bonus is or isn't earned, and the vault each VT video shows, by its name in the Infinity vault chart; a vault without one is checked by value). python tools/build_calibration.py reads both and the video folder (orientation from Drive) and writes calibration/infinity/routines.js; it needs the UCG Google sign-in, so it runs locally, and its output is committed./?calibration=BB_2: the planner skips sign-in and opens that routine alone, as a guest that can't sign in (nothing is read from or saved to an account), with a banner back to judge practice (js/calibration-view.js, loaded only for such a link; openCalibration in app.js). Each skill becomes the listed skill it clearly is (closestSkill, same value and condensed group; about 120 of 189) or stays as the sheet names it; the start value is the key's either way (tested).calibration/infinity/key.js runs each key through scoreInfinity (js/scoring/wag.js). tests/calibration.test.mjs fails if that disagrees with the sheet's start value, and the page shows a warning if it ever does.drive.google.com). The service worker serves it as itself (a folder without its slash redirects, as on GitHub Pages) and, on install, also puts the site's extra pages into older versions' caches: a device still running a worker from before this page existed shows the planner's blank "Loading…" on the first visit, and the page from the next reload on.https://routines.unitedclubgymnastics.org/calibration/mag/ (calibration/mag/): judges practise UCG MAG on 18 calibration routines (Developmental, Intermediate and Advanced, each apparatus): the whole score, not just difficulty. The calculator follows the old MAG judging calculator: each counting skill's value (Sub-A to F) and element group, the apparatus's bonuses and stick bonus, the missing requirements and other neutral deductions, and one execution total. Did I get it right? checks the start value and neutral deductions exactly and the execution total within ±0.3 (E_TOLERANCE), and says what differs; See the routine laid out lists every skill with its credit and every execution and neutral deduction with the judges' comments. Videos are the doc's YouTube (privacy-enhanced embeds) and Drive links.
calibration/mag/routines.js, from last season's NAIGC MAG 2026 Example Routine Evaluations doc (DOC_URL) brought up to the 2026-28 UCG MAG rules: each skill is the listed skill it is (skillId, this season's value and group: several no-EG A skills are now Sub-A), or keeps the doc's value where there's no clear match. Edit it there; tests/calibration-mag.test.mjs pins each key and checks every skill against the skill list, and every execution total against its deductions.calibration/mag/key.js runs each routine through scoreRoutine / scoreVault (js/scoring/mag.js), plus the stick bonus (the level's cap includes it) and the judges' own neutral deductions; the judge's entry goes through the same engine. Skills the judges didn't recognise for another reason than repetition are notRecognised (scored as nothing, flagged "Not recognised" in the planner)./?calibration=mag/adv-fx: the routine at its MAG level (vault too). The stick bonus isn't part of a plan, so the planner's start value is the key's less the stick (the banner says so).calibration/mag/practice.css, and it may also frame www.youtube-nocookie.com.From a clone: Node 22 (npm ci), and for the data tools Python 3.13 with pip install jsonschema rfc3987
(npm run sync-skills validates the bundle against its schemas; tools/build_skills.py and tools/build_data.py
need only the standard library). npm run sync-skills also needs the gym-skill-extract checkout
(GYM_SKILL_EXTRACT_DIR, default C:/dev/gym-skill-extract); everything else builds from this repo alone.
The browser smoke test needs npx playwright install chromium once.
npm start # serves the source on http://localhost:8080 (no build needed)
npm test # scoring tests (Node 20+)
Open http://localhost:8080/?local to try it without signing in (saved in that browser only). In development the files load as they are: Firebase and pdf-lib come from their CDNs, and there's no service worker.
Julia Sharpe's UCG Infinity SV Sheets (jzsharpe.github.io/ucg-infinity-sv, Firebase project ucg-infinity-sv-generator) is replaced by this planner. Signed-in members use Bring over UCG Infinity routines (the athlete switcher in the header) or Import from UCG Infinity (the first-run screen): js/import-infinity.js signs them in to the old project with Google (a second Firebase app), reads users/{uid}/athletes, and converts each into an athlete with a UCG Infinity level (bars/beam/floor -> ub/bb/fx; apparatus bonus; the vault matched by name and saved by its id; each typed skill becomes the listed skill it clearly is, via closestSkill in js/skill-search.js: among skills with the same value and USAG group, every typed word in its name or nicknames, closest name first (descriptive extras like landing / step-out / jump / turn count half), at most 2 extra words (half a word for a one-word name), and closer than any rival; such rows keep matchedFrom and are flagged "Matched" until edited; the rest stay as typed). Imported athletes carry importedFrom: "infinity-sv:<old id>", so they aren't brought twice. Start values are identical: the conversion was checked against the old planner's own scoring on 8,000+ random routines. The old project must list routines.unitedclubgymnastics.org under Authentication -> Authorized domains, and must stay in place for as long as members may still import.
Every pull request and push to main runs the check job of .github/workflows/pages.yml: npm ci --ignore-scripts (+ npm rebuild esbuild), npm run check-bundle, js/data rebuilt by both Python builders and compared, the scoring tests, npm run build, a browser smoke test of the build. On main the deploy job then publishes that _site/ to GitHub Pages. To do the same locally:
npm ci # once: esbuild, Firebase, pdf-lib, Playwright
npm run build # -> _site/
npm run preview # http://localhost:8139/ucg-routine-planner/ (like GitHub Pages)
npx playwright install chromium # once
npm run smoke # browser smoke test of _site/
What the build does (tools/build_site.mjs):
js/app.js with esbuild, with code splitting and hashed file names. Startup is about 140 KB of JavaScript. Firebase, PDF export, the skill catalog and each discipline's skill lists (loadDiscipline in js/skill-search.js) are separate chunks, loaded on demand and fetched ahead (on hovering a level, Export PDF, or showing the copy panel).CDN in the build script), so the live site doesn't depend on those CDNs. If you add a CDN import, pin it there too or the build fails.<meta> tags to index.html and privacy.html (judge practice has its own; see above) (GitHub Pages can't send headers). Scripts come only from the site itself and Google sign-in (apis.google.com); frames only from the two Firebase sign-in domains; connections to the site, *.googleapis.com and the feedback form. The page has no inline script (the build fails if one appears): the service worker is registered from app.js. Turning App Check on adds the reCAPTCHA hosts. A smoke test opens Google sign-in and fails on any refused load.sw.js (from tools/sw-template.js): a service worker that stores every file of the build on the device (about 1.25 MB, once). The planner opens instantly and works offline, including PDF export. Each build is a version; after a deploy, open pages show "A new version of the planner is ready — Reload".firestore.rules): each user reads and writes only users/{uid}/athletes/{id} (and magAthletes, which the MAG-only planner in the same Firebase project still uses). Athlete documents may hold only name, club, entries, createdAt, updatedAt, importedFrom, schemaVersion; name and club are at most 200 characters, at most 40 entries. Rules are not deployed by the site's deploy: after a change, run firebase deploy --only firestore:rules (Firebase CLI, signed in with an account that can edit project ucg-routine-planners). Deploy a rules change together with or after the app change it needs.npm run test:rules runs tests/rules.test.mjs on the Firestore emulator (needs the Firebase CLI and Java 11+). Under plain npm test they skip.appCheck in js/firebase-config.js. Turn it on only after the web app is registered under App Check in the Firebase console; enforce it for Firestore only once the deployed site sends tokens (the console's App Check metrics show it).privacy.html is a short planner note under UCG's own privacy policy (the PDF on unitedclubgymnastics.org), with UCG's contact page for questions. It's linked from the footer, the sign-in screen and the account menu. The account menu also has Export my data (a JSON download of everything saved, from the server) and Delete all my data (asks twice; deletes every athlete in athletes and magAthletes, then the sign-in; Google may ask to sign in again first). Signing out clears the device's offline copy (terminate + clearIndexedDbPersistence) and reloads; if edits haven't reached the server it asks first. Feedback reports carry no athlete name and the page address without its query or #.Offline data: Firestore keeps a copy on the device. Edits save there with no signal ("Saved on this device · will sync when online") and sync later. Changes made on another device arrive live, but never redraw the screen while you're typing ("Changed on another device — Load latest").
Fonts are served from assets/fonts/. The brand typefaces, Greed Condensed (titles, numbers, buttons) and Suisse Intl (everything else), are licensed, so their files (GreedCondensed-Bold.woff2, SuisseIntl-Regular.woff2, SuisseIntl-RegularIt.woff2, SuisseIntl-Bold.woff2) are kept out of git (.gitignore). When they're in assets/fonts/, the build adds them to the stylesheet; without them the planner uses Saira Condensed (OFL, in the repo) and Arial.
UCG Design System (2026 identity): navy / blue green / light blue, condensed caps for titles, numbers and buttons only (Greed Condensed, or Saira Condensed without it), sentence-case labels in the body face, 20px cards. One header bar (athlete switcher, account menu with feedback and sign in/out); the athlete's name and club on a navy band; an event strip with each start value. On phones, skills fold to two lines and open to edit, and the open event's start value stays in a bar at the bottom (Breakdown opens its parts). Discipline badges: WAG purple, MAG navy, T&T dark blue green.
calibration/infinity/| Judge practice for UCG Infinity difficulty (its own page; see "Judge practice") |
rules/UCG-MASTERS/digest/scoring.jsonjs/data/masters-rules.jsrules/WG-MAG-2025/digest/composition.jsonjs/data/wg-mag-rules.jsrules/USAG-XCEL-2022/digest/same-element.jsonunsurewagSkillAllowedjs/skill-search.jspython tools/build_data.pydata/tt-skills.js | UCG T&T DD charts incl. the UCG addendum (tools/source/tt_skills.json) | python tools/build_data.py |
data/examples.js | T&T, MAG Dev/Int and WAG Xcel example routine sheets (tools/source/examples.json, typos fixed; WAG skills matched to the Xcel list, see tools/source/examples_notes.md). T&T example skills found in the DD chart take the chart's shorthand and DD (some sheets predate the UCG addendum). Examples that break their level's rules are left out (EXCLUDE in build_data.py; node tools/check_examples.mjs lists them, and a test keeps the rest clean) | python tools/build_data.py |
data/xcel.js | Bundle rules/USAG-XCEL-2022/digest/levels.json: the Xcel value parts, difficulty limits, special requirements and vault charts | python tools/build_data.py |
data/infinity-rules.js | Bundle rules/UCG-WAG/digest/infinity.json (values, counting, bonuses, element group names, event-bonus labels) + catalog/levels.json (condensed groups); js/scoring/wag.js re-exports them | python tools/build_data.py |
data/wag-infinity-vaults.js | Bundle rules/UCG-WAG/digest/infinity-vaults.json (the Infinity Rules' full vault chart, source of record) + the permanent ids in tools/source/infinity_vault_ids.json (INF-001 ..., matched by name), which routines save: never reuse or renumber one; when the chart renames a vault, rename it there and list the old name in was. The build fails on a row with no id or an id with no row | python tools/build_data.py |
assets/worksheets/tt-*.pdf | 2023 NAIGC competition cards, logo removed, requirement boxes corrected | python tools/make_tt_cards.py |