├── .github └── workflows │ └── pages.yml ├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── dist ├── WcaOauth.php ├── baidutongji.php ├── cache.manifest ├── css │ └── .gitkeep ├── cstimer.webmanifest ├── cstimer512x512.png ├── js │ ├── .gitkeep │ └── jquery.min.js ├── lang │ └── .gitkeep ├── oauthwca.php ├── sw.js ├── timer.php ├── userdata.php ├── userdata2.php └── wsServer.js ├── experiment ├── bleHack.js ├── grip.js └── puzzleAnalyze.js ├── lib ├── compiler.jar └── jquery-1.7.js ├── npm_export ├── README.md ├── cstimer_module.d.ts ├── package.json └── testbench │ ├── en-us.js │ └── test.js └── src ├── WcaOauth.php ├── cache.manifest ├── css └── style.css ├── cstimer.webmanifest ├── cstimer512x512.png ├── index.php ├── js ├── cstimer.js ├── export.js ├── hardware │ ├── bluetooth.js │ ├── gancube.js │ ├── gantimer.js │ ├── giikercube.js │ ├── gocube.js │ ├── moyu32cube.js │ ├── moyucube.js │ ├── qiyicube.js │ └── stackmat.js ├── help.js ├── kernel.js ├── lib │ ├── cubeutil.js │ ├── grouplib.js │ ├── isaac.js │ ├── jquery-1.8.0.js │ ├── lzstring.js │ ├── mathlib.js │ ├── min2phase.js │ ├── pat3x3.js │ ├── pnltri.js │ ├── poly3dlib.js │ ├── puzzlefactory.js │ ├── sbtree.js │ ├── sha256.js │ ├── sqlfile.js │ ├── storage.js │ ├── tdconverter.js │ ├── threemin.js │ └── utillib.js ├── logohint.js ├── scramble │ ├── 1x3x3.js │ ├── 2x2x2.js │ ├── 2x2x3.js │ ├── 333lse.js │ ├── clock.js │ ├── gearcube.js │ ├── kilominx.js │ ├── megascramble.js │ ├── mgmlsll.js │ ├── pyraminx.js │ ├── redi.js │ ├── scramble.js │ ├── scramble_333_edit.js │ ├── scramble_444.js │ ├── scramble_fto.js │ ├── scramble_sq1_new.js │ ├── skewb.js │ ├── slide.js │ └── utilscramble.js ├── shortcut.js ├── solver │ ├── ftocta.js │ └── kilominx.js ├── stats │ ├── distribution.js │ ├── dlystat.js │ ├── hugestat.js │ ├── recons.js │ ├── stats.js │ ├── stattool.js │ ├── timestat.js │ ├── trainstat.js │ └── trend.js ├── timer.js ├── timer │ ├── gan.js │ ├── giiker.js │ ├── input.js │ ├── stackmat.js │ └── virtual.js ├── tools │ ├── battle.js │ ├── bldhelper.js │ ├── bluetoothutil.js │ ├── cross.js │ ├── eoline.js │ ├── gsolver.js │ ├── image.js │ ├── metronome.js │ ├── onlinecomp.js │ ├── pat3x3gen.js │ ├── roux1.js │ ├── stackmatutil.js │ ├── syncseed.js │ ├── thistlethwaite.js │ └── tools.js ├── twisty │ ├── qcube.js │ ├── qcubeclk.js │ ├── qcubeminx.js │ ├── qcubennn.js │ ├── twisty.js │ ├── twistyclk.js │ ├── twistynnn.js │ ├── twistypoly.js │ ├── twistyreplay.js │ ├── twistyskb.js │ └── twistysq1.js └── worker.js ├── lang ├── ar-sa.js ├── ar-sa.php ├── bn-bd.js ├── bn-bd.php ├── ca-es.js ├── ca-es.php ├── color.php ├── cs-cz.js ├── cs-cz.php ├── da-dk.js ├── da-dk.php ├── de-de.js ├── de-de.php ├── el-gr.js ├── el-gr.php ├── en-us.js ├── en-us.php ├── es-es.js ├── es-es.php ├── fa-ir.js ├── fa-ir.php ├── fi-fi.js ├── fi-fi.php ├── fr-fr.js ├── fr-fr.php ├── he-il.js ├── he-il.php ├── hi-in.js ├── hi-in.php ├── hr-hr.js ├── hr-hr.php ├── hu-hu.js ├── hu-hu.php ├── it-it.js ├── it-it.php ├── ja-jp.js ├── ja-jp.php ├── ko-kr.js ├── ko-kr.php ├── lang.php ├── langDet.php ├── lv-lv.js ├── lv-lv.php ├── nl-nl.js ├── nl-nl.php ├── no-no.js ├── no-no.php ├── pl-pl.js ├── pl-pl.php ├── pt-pt.js ├── pt-pt.php ├── ro-ro.js ├── ro-ro.php ├── ru-ru.js ├── ru-ru.php ├── sk-sk.js ├── sk-sk.php ├── sl-si.js ├── sl-si.php ├── sr-sp.js ├── sr-sp.php ├── sv-se.js ├── sv-se.php ├── tr-tr.js ├── tr-tr.php ├── uk-ua.js ├── uk-ua.php ├── vi-vn.js ├── vi-vn.php ├── zh-cn.js ├── zh-cn.php ├── zh-tw.js └── zh-tw.php ├── oauthwca.php └── sw.js /.github/workflows/pages.yml: -------------------------------------------------------------------------------- 1 | name: Deploy to Github Pages 2 | 3 | on: 4 | push: 5 | branches: ["master"] 6 | 7 | workflow_dispatch: 8 | 9 | permissions: 10 | contents: read 11 | pages: write 12 | id-token: write 13 | 14 | concurrency: 15 | group: "pages" 16 | cancel-in-progress: false 17 | 18 | jobs: 19 | deploy: 20 | environment: 21 | name: github-pages 22 | url: ${{ steps.deployment.outputs.page_url }} 23 | runs-on: ubuntu-latest 24 | steps: 25 | - name: Checkout 26 | uses: actions/checkout@v4 27 | - name: Setup java 28 | uses: actions/setup-java@v4.0.0 29 | with: 30 | distribution: 'temurin' 31 | java-version: '11' 32 | - name: Setup php 33 | uses: shivammathur/setup-php@2.28.0 34 | with: 35 | php-version: '8.0' 36 | - name: Build cstimer 37 | run: mkdir dist/local dist/local/js dist/local/css && make local 38 | - name: Setup Pages 39 | uses: actions/configure-pages@v4 40 | - name: Upload artifact 41 | uses: actions/upload-pages-artifact@v3 42 | with: 43 | path: 'dist/local' 44 | - name: Deploy to GitHub Pages 45 | id: deployment 46 | uses: actions/deploy-pages@v4 47 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /dist 2 | /.idea 3 | cstimer.iml -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | src = src 2 | ifndef dest 3 | dest = dist 4 | endif 5 | ifndef destnpm 6 | destnpm = npm_export 7 | endif 8 | closure = lib/compiler.jar 9 | compile = java -jar $(closure) --use_types_for_optimization --language_out STABLE --charset UTF-8 --strict_mode_input 10 | isolation = --isolation_mode IIFE 11 | advanced = -O ADVANCED 12 | debugoff = --define='DEBUGM=false' --define='DEBUGWK=false' 13 | timerSrc = $(addprefix $(src)/js/, \ 14 | lib/utillib.js \ 15 | lib/sha256.js \ 16 | lib/isaac.js \ 17 | lib/mathlib.js \ 18 | lib/grouplib.js \ 19 | lib/poly3dlib.js \ 20 | lib/pat3x3.js \ 21 | lib/sbtree.js \ 22 | lib/sqlfile.js \ 23 | lib/tdconverter.js \ 24 | lib/lzstring.js \ 25 | lib/min2phase.js \ 26 | lib/cubeutil.js \ 27 | lib/puzzlefactory.js \ 28 | kernel.js \ 29 | export.js \ 30 | logohint.js \ 31 | timer.js \ 32 | timer/input.js \ 33 | timer/stackmat.js \ 34 | timer/gan.js \ 35 | timer/virtual.js \ 36 | timer/giiker.js \ 37 | solver/ftocta.js \ 38 | solver/kilominx.js \ 39 | scramble/scramble.js \ 40 | scramble/megascramble.js \ 41 | scramble/scramble_333_edit.js \ 42 | scramble/scramble_444.js \ 43 | scramble/scramble_sq1_new.js \ 44 | scramble/pyraminx.js \ 45 | scramble/skewb.js \ 46 | scramble/2x2x2.js \ 47 | scramble/gearcube.js \ 48 | scramble/1x3x3.js \ 49 | scramble/2x2x3.js \ 50 | scramble/clock.js \ 51 | scramble/333lse.js \ 52 | scramble/mgmlsll.js \ 53 | scramble/kilominx.js \ 54 | scramble/scramble_fto.js \ 55 | scramble/redi.js \ 56 | scramble/slide.js \ 57 | scramble/utilscramble.js \ 58 | lib/storage.js \ 59 | stats/timestat.js \ 60 | stats/stats.js \ 61 | stats/stattool.js \ 62 | stats/trend.js \ 63 | stats/distribution.js \ 64 | stats/hugestat.js \ 65 | stats/dlystat.js \ 66 | stats/recons.js \ 67 | stats/trainstat.js \ 68 | tools/tools.js \ 69 | tools/image.js \ 70 | tools/cross.js \ 71 | tools/eoline.js \ 72 | tools/roux1.js \ 73 | tools/gsolver.js \ 74 | tools/thistlethwaite.js \ 75 | tools/pat3x3gen.js \ 76 | tools/bluetoothutil.js \ 77 | tools/metronome.js \ 78 | tools/onlinecomp.js \ 79 | tools/battle.js \ 80 | tools/syncseed.js \ 81 | tools/bldhelper.js \ 82 | twisty/twistyreplay.js \ 83 | shortcut.js \ 84 | help.js \ 85 | hardware/stackmat.js \ 86 | tools/stackmatutil.js \ 87 | hardware/bluetooth.js \ 88 | hardware/giikercube.js \ 89 | hardware/gocube.js \ 90 | hardware/gancube.js \ 91 | hardware/moyucube.js \ 92 | hardware/moyu32cube.js \ 93 | hardware/qiyicube.js \ 94 | hardware/gantimer.js \ 95 | worker.js) 96 | 97 | cache = $(addprefix $(dest)/, \ 98 | timer.php \ 99 | js/cstimer.js \ 100 | js/twisty.js \ 101 | css/style.css) $(langJS) $(langPHP) 102 | 103 | twistySrc = $(addprefix $(src)/js/, \ 104 | lib/threemin.js \ 105 | lib/pnltri.js \ 106 | twisty/twisty.js \ 107 | twisty/twistynnn.js \ 108 | twisty/twistysq1.js \ 109 | twisty/twistyskb.js \ 110 | twisty/twistyclk.js \ 111 | twisty/twistypoly.js \ 112 | twisty/qcube.js \ 113 | twisty/qcubennn.js \ 114 | twisty/qcubeminx.js \ 115 | twisty/qcubeclk.js) 116 | 117 | moduleSrc = $(addprefix $(src)/js/, \ 118 | lib/utillib.js \ 119 | lib/isaac.js \ 120 | lib/mathlib.js \ 121 | lib/grouplib.js \ 122 | lib/poly3dlib.js \ 123 | lib/pat3x3.js \ 124 | lib/min2phase.js \ 125 | lib/cubeutil.js \ 126 | solver/ftocta.js \ 127 | solver/kilominx.js \ 128 | scramble/scramble.js \ 129 | scramble/megascramble.js \ 130 | scramble/scramble_333_edit.js \ 131 | scramble/scramble_444.js \ 132 | scramble/scramble_sq1_new.js \ 133 | scramble/pyraminx.js \ 134 | scramble/skewb.js \ 135 | scramble/2x2x2.js \ 136 | scramble/gearcube.js \ 137 | scramble/1x3x3.js \ 138 | scramble/2x2x3.js \ 139 | scramble/clock.js \ 140 | scramble/333lse.js \ 141 | scramble/mgmlsll.js \ 142 | scramble/kilominx.js \ 143 | scramble/scramble_fto.js \ 144 | scramble/redi.js \ 145 | scramble/slide.js \ 146 | scramble/utilscramble.js \ 147 | tools/tools.js \ 148 | tools/image.js \ 149 | tools/cross.js \ 150 | worker.js) 151 | 152 | cstimer = $(dest)/js/cstimer.js 153 | twisty = $(dest)/js/twisty.js 154 | cstimer_module = $(destnpm)/cstimer_module.js 155 | css = $(addprefix $(dest)/css/, $(shell ls $(src)/css)) 156 | langJS = $(addprefix $(dest)/lang/, $(shell ls $(src)/lang/ | grep .*\.js)) 157 | langPHP = $(addprefix $(dest)/lang/, $(shell ls $(src)/lang/ | grep .*\.php)) 158 | 159 | version := $(shell git describe --tags --always 2>/dev/null || echo Unspecified) 160 | 161 | all: $(cstimer) $(twisty) $(css) $(langJS) $(langPHP) version $(dest)/cache.manifest $(dest)/sw.js 162 | 163 | module: $(cstimer_module) 164 | 165 | version: $(langPHP) 166 | @echo "Build Version: $(version)" 167 | @sed -i 's/\$$version = "[^"]*"/\$$version = "$(version)"/g' $(dest)/lang/langDet.php 168 | 169 | clean: 170 | rm -f $(cstimer) $(twisty) $(css) $(langJS) $(langPHP) 171 | 172 | local: all 173 | mkdir -p $(dest)/local/js $(dest)/local/css 174 | php -d include_path=$(dest) $(dest)/timer.php | sed "s/.*manifest.*//g" > $(dest)/local/index.html 175 | cp $(dest)/js/jquery.min.js $(dest)/local/js/jquery.min.js 176 | cp $(dest)/js/cstimer.js $(dest)/local/js/cstimer.js 177 | cp $(dest)/js/twisty.js $(dest)/local/js/twisty.js 178 | cp $(dest)/css/style.css $(dest)/local/css/style.css 179 | 180 | $(cstimer): $(twisty) $(timerSrc) 181 | @echo $@ 182 | @$(compile) $(debugoff) $(timerSrc) --js_output_file $(cstimer) 183 | 184 | $(twisty): $(twistySrc) 185 | @echo $@ 186 | @$(compile) $(twistySrc) --js_output_file $(twisty) 187 | 188 | $(cstimer_module): $(moduleSrc) 189 | @echo $@ 190 | @$(compile) $(debugoff) $(moduleSrc) $(isolation) --define='ISCSTIMER=false' --js_output_file $(cstimer_module) 191 | 192 | $(css): $(dest)/css/%.css: $(src)/css/%.css 193 | @echo $@ 194 | @cp $< $@ 195 | 196 | $(langPHP): $(dest)/lang/%: $(src)/lang/% 197 | @echo $@ 198 | @cp $< $@ 199 | 200 | $(langJS): $(dest)/lang/%: $(src)/lang/% 201 | @echo $@ 202 | @$(compile) $< --js_output_file $@ 203 | 204 | $(dest)/cache.manifest: $(cache) version 205 | @echo $@ 206 | @sed -i '$$d' $@ 207 | @echo -n \# MD5= >> $@ 208 | @cat $(cache) | md5sum | awk '{print $$1}' >> $@ 209 | 210 | $(dest)/sw.js: $(cache) version 211 | @echo $@ 212 | @sed -i '$$d' $@ 213 | @echo 'var CACHE_NAME = "cstimer_cache_'`cat $(cache) | md5sum | awk '{print $$1}'`'";' >> $@ 214 | 215 | .PHONY: all clean version 216 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # csTimer 2 | 3 | Professional Speedcubing/Training Timer 4 | 5 | 6 | # Versions and Update Policy 7 | 8 | Main version: https://cstimer.net/ 9 | 10 | Latest version: https://cstimer.net/new/ 11 | 12 | Source version: https://cstimer.net/src/ 13 | 14 | [Latest version](https://cstimer.net/new/) and [Source version](https://cstimer.net/src/) will always be the same as the [master](https://github.com/cs0x7f/csTimer/tree/master) branch of this project. While [Main version](https://cstimer.net/) will always be the same as [released](https://github.com/cs0x7f/csTimer/tree/released) branch of this project. 15 | 16 | New features will firstly be implemented in [Latest version](https://cstimer.net/new/). After testing for several days, [Main version](https://cstimer.net/) will be updated if appropriate, depends on user feedback for the new function or update. 17 | 18 | It is preferred to use HTTPS protocol to visit csTimer. Although HTTP is available, some functions might not work correctly, e.g. stackmatTimer, WCA login, etc. 19 | 20 | 21 | # Using as Native APP 22 | 23 | Currently, csTimer is able to work as a native app on mobile devices owing to [Progressive Web Apps](https://developers.google.com/web/progressive-web-apps/). Thus, when you open csTimer by chrome or some other modern browser on mobile devices, it will ask you whether to add csTimer to home screen. Then, you can use csTimer as a native app that also works without network access. 24 | 25 | 26 | # Translation 27 | 28 | [![Crowdin](https://badges.crowdin.net/cstimer/localized.svg)](https://crowdin.com/project/cstimer) 29 | 30 | If you are willing to help translating cstimer into your native language, please go to [this](https://crowdin.com/project/cstimer) page and select your language. If your native language is not on the list, just contact me and I'll add it. 31 | 32 | 33 | # Data Storage 34 | 35 | Currently, all data (including settings, session data, etc) are stored in user browser's storage. More specificently, all settings are stored in localStorage, while session data (except session meta data) are stored in indexedDB or localStorage if indexedDB is not available. 36 | 37 | Therefore, all data will be lost if you clear browser cache. For avoiding data loss, you might use the "export" function to export/import all your data to/from a file, csTimer's server or google storage. 38 | 39 | # Data Imported to csTimer's Server / Google Storage 40 | 41 | After [8280fda](https://github.com/cs0x7f/cstimer/commit/8280fdab9628c605c9abc1bc4a127e3e84016542), you are able to download data that is uploaded before the latest one from csTimer's Server / Google Storage, which might be useful for a mis-uploading. For Google Storage, csTimer will keep 10 latest uploaded data. For csTimer's server, 10 or more latest uploaded data will be kept. More specificently, I'll keep 10 latest uploaded data while others might be deleted due to our limited disk resource. 42 | 43 | 44 | # Third-party Deployment 45 | 46 | Some functions of csTimer might not work properly for domains except "cstimer.net", especially online-based export/import functions due to callback address verification. If you want to make csTimer work as a part of your own website, it is recommended to use