├── tlp-recorder ├── credentials │ └── .gitkeep ├── jest.setup.ts ├── .prettierrc ├── prisma │ ├── migrations │ │ ├── 20220525200402_added_match_recorded │ │ │ └── migration.sql │ │ ├── migration_lock.toml │ │ ├── 20220525115543_init │ │ │ └── migration.sql │ │ ├── 20220525134753_match_stage_mandatory │ │ │ └── migration.sql │ │ ├── 20220525134836_match_add_ranks │ │ │ └── migration.sql │ │ ├── 20220525200529_match_recorded_not_optional │ │ │ └── migration.sql │ │ ├── 20220525194814_match_created_at_updated_at │ │ │ └── migration.sql │ │ └── 20220525132132_split_up_match_outcome_column │ │ │ └── migration.sql │ └── schema.prisma ├── .env.sample ├── src │ ├── tekken │ │ ├── notation.ts │ │ ├── offsets.ts │ │ ├── parser.ts │ │ └── state.ts │ ├── types │ │ ├── memoryjs.d.ts │ │ └── types.ts │ ├── helpers │ │ ├── memory.ts │ │ ├── log.ts │ │ └── environment.ts │ ├── __tests__ │ │ └── environment.test.ts │ ├── database.ts │ ├── recording │ │ ├── util.ts │ │ ├── youtube │ │ │ ├── uploader.ts │ │ │ └── auth.ts │ │ └── obs │ │ │ └── broker.ts │ ├── config.ts │ └── index.ts ├── jest.config.ts ├── .eslintrc.json ├── tsconfig.json ├── .vscode │ └── launch.json ├── package.json └── .gitignore ├── tlp-webapp ├── .env.development ├── .env.production ├── .eslintrc ├── src │ ├── components │ │ ├── Layout │ │ │ ├── index.ts │ │ │ ├── Header │ │ │ │ ├── index.ts │ │ │ │ └── Header.tsx │ │ │ ├── Navigator │ │ │ │ ├── index.ts │ │ │ │ ├── NavigationLink │ │ │ │ │ ├── index.ts │ │ │ │ │ └── NavigationLink.tsx │ │ │ │ └── Navigator.tsx │ │ │ └── Layout.tsx │ │ └── common │ │ │ ├── PageTitle.tsx │ │ │ ├── BrandLogo.tsx │ │ │ ├── Breadcrumbs.tsx │ │ │ ├── Error.tsx │ │ │ ├── YoutubeEmbed.tsx │ │ │ ├── DeleteButtonWithConfirmation.tsx │ │ │ └── Outcome.tsx │ ├── modules │ │ ├── widgets │ │ │ ├── index.ts │ │ │ ├── useWeeklyPerformance.tsx │ │ │ ├── WeeklyWinrate.tsx │ │ │ └── WeeklyPerformance.tsx │ │ ├── settings │ │ │ ├── index.ts │ │ │ ├── useSettings.ts │ │ │ ├── useSettingsForm.ts │ │ │ └── SettingsForm.tsx │ │ ├── rivals │ │ │ ├── index.ts │ │ │ ├── useRivals.ts │ │ │ ├── useRival.ts │ │ │ ├── RivalsTableRow.tsx │ │ │ └── RivalsTable.tsx │ │ ├── dashboard │ │ │ ├── useCharacters.ts │ │ │ ├── useCharacterSummary.ts │ │ │ ├── StagesTableRow.tsx │ │ │ ├── MatchupsTableRow.tsx │ │ │ ├── index.ts │ │ │ ├── CharactersTableRow.tsx │ │ │ ├── CharacterOverview.tsx │ │ │ ├── StagesTable.tsx │ │ │ ├── CharactersTable.tsx │ │ │ └── MatchupsTable.tsx │ │ └── matchHistory │ │ │ ├── useDeleteMatch.ts │ │ │ ├── index.ts │ │ │ ├── useMatch.ts │ │ │ ├── useMatches.ts │ │ │ ├── MatchVideo.tsx │ │ │ ├── MatchesTableRow.tsx │ │ │ └── MatchesTable.tsx │ ├── pages │ │ ├── index.tsx │ │ ├── rivals │ │ │ └── index.tsx │ │ ├── _document.tsx │ │ ├── history │ │ │ ├── index.tsx │ │ │ └── [id].tsx │ │ ├── dashboard │ │ │ ├── index.tsx │ │ │ └── [character].tsx │ │ ├── api │ │ │ ├── matches │ │ │ │ ├── index.ts │ │ │ │ ├── [id].ts │ │ │ │ └── weeklyPerformance.ts │ │ │ ├── characters │ │ │ │ ├── index.ts │ │ │ │ └── [character].ts │ │ │ ├── rivals │ │ │ │ └── index.ts │ │ │ └── settings │ │ │ │ └── index.ts │ │ ├── settings │ │ │ └── index.tsx │ │ └── _app.tsx │ └── lib │ │ ├── util.ts │ │ ├── database.ts │ │ └── types.ts ├── public │ ├── favicon.ico │ ├── images │ │ └── characters │ │ │ ├── Anna.png │ │ │ ├── Bob.png │ │ │ ├── Eddy.png │ │ │ ├── Feng.png │ │ │ ├── Jin.png │ │ │ ├── King.png │ │ │ ├── Kuma.png │ │ │ ├── Lars.png │ │ │ ├── Law.png │ │ │ ├── Lee.png │ │ │ ├── Lei.png │ │ │ ├── Leo.png │ │ │ ├── Lili.png │ │ │ ├── Nina.png │ │ │ ├── Paul.png │ │ │ ├── Akuma.png │ │ │ ├── Alisa.png │ │ │ ├── Asuka.png │ │ │ ├── Bryan.png │ │ │ ├── Claudio.png │ │ │ ├── Eliza.png │ │ │ ├── Ganryu.png │ │ │ ├── Geese.png │ │ │ ├── Gigas.png │ │ │ ├── Jack 7.png │ │ │ ├── Josie.png │ │ │ ├── Julia.png │ │ │ ├── Kazumi.png │ │ │ ├── Kazuya.png │ │ │ ├── Leroy.png │ │ │ ├── Lidia.png │ │ │ ├── Marduk.png │ │ │ ├── Miguel.png │ │ │ ├── Negan.png │ │ │ ├── Noctis.png │ │ │ ├── Panda.png │ │ │ ├── Shaheen.png │ │ │ ├── Steve.png │ │ │ ├── Xiaoyu.png │ │ │ ├── Zafina.png │ │ │ ├── Devil Jin.png │ │ │ ├── Dragunov.png │ │ │ ├── Fahkumram.png │ │ │ ├── Heihachi.png │ │ │ ├── Hwoarang.png │ │ │ ├── Katarina.png │ │ │ ├── Kunimitsu.png │ │ │ ├── Armor King.png │ │ │ ├── Lucky Chloe.png │ │ │ ├── Master Raven.png │ │ │ └── Yoshimitsu.png │ └── Logo.svg ├── .prettierrc ├── prisma │ ├── migrations │ │ ├── 20220525200402_added_match_recorded │ │ │ └── migration.sql │ │ ├── migration_lock.toml │ │ ├── 20220525115543_init │ │ │ └── migration.sql │ │ ├── 20220525134753_match_stage_mandatory │ │ │ └── migration.sql │ │ ├── 20220525134836_match_add_ranks │ │ │ └── migration.sql │ │ ├── 20220525200529_match_recorded_not_optional │ │ │ └── migration.sql │ │ ├── 20220525194814_match_created_at_updated_at │ │ │ └── migration.sql │ │ └── 20220525132132_split_up_match_outcome_column │ │ │ └── migration.sql │ └── schema.prisma ├── next.config.js ├── next-env.d.ts ├── .gitignore ├── server.js ├── tsconfig.json ├── README.md └── package.json ├── bin ├── database.db ├── start_recorder.bat ├── start_webapp.bat ├── start_all.bat └── config.yaml ├── docs ├── rivals.png ├── dashboard.png ├── match_detail.png ├── match_history.png └── character_detail.png ├── .github └── workflows │ ├── main.yml │ └── codeql-analysis.yml └── README.md /tlp-recorder/credentials/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tlp-webapp/.env.development: -------------------------------------------------------------------------------- 1 | NODE_ENV=development -------------------------------------------------------------------------------- /tlp-webapp/.env.production: -------------------------------------------------------------------------------- 1 | NODE_ENV=production -------------------------------------------------------------------------------- /tlp-recorder/jest.setup.ts: -------------------------------------------------------------------------------- 1 | process.env.FOO = 'bar'; 2 | 3 | export {}; 4 | -------------------------------------------------------------------------------- /tlp-webapp/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next", 3 | "root": true 4 | } 5 | -------------------------------------------------------------------------------- /bin/database.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcelherd/TekkenLearningPlatform/HEAD/bin/database.db -------------------------------------------------------------------------------- /bin/start_recorder.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | cmd /C "set "NODE_ENV=production" && start tlp-recorder.exe" 3 | -------------------------------------------------------------------------------- /bin/start_webapp.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | cmd /C "set "NODE_ENV=production" && start tlp-webapp.exe" 3 | -------------------------------------------------------------------------------- /docs/rivals.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcelherd/TekkenLearningPlatform/HEAD/docs/rivals.png -------------------------------------------------------------------------------- /docs/dashboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcelherd/TekkenLearningPlatform/HEAD/docs/dashboard.png -------------------------------------------------------------------------------- /docs/match_detail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcelherd/TekkenLearningPlatform/HEAD/docs/match_detail.png -------------------------------------------------------------------------------- /docs/match_history.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcelherd/TekkenLearningPlatform/HEAD/docs/match_history.png -------------------------------------------------------------------------------- /tlp-webapp/src/components/Layout/index.ts: -------------------------------------------------------------------------------- 1 | export { default } from './Layout'; 2 | export * from './Layout'; 3 | -------------------------------------------------------------------------------- /tlp-webapp/src/components/Layout/Header/index.ts: -------------------------------------------------------------------------------- 1 | export { default } from './Header'; 2 | export * from './Header'; 3 | -------------------------------------------------------------------------------- /docs/character_detail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcelherd/TekkenLearningPlatform/HEAD/docs/character_detail.png -------------------------------------------------------------------------------- /tlp-webapp/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcelherd/TekkenLearningPlatform/HEAD/tlp-webapp/public/favicon.ico -------------------------------------------------------------------------------- /tlp-webapp/src/components/Layout/Navigator/index.ts: -------------------------------------------------------------------------------- 1 | export { default } from './Navigator'; 2 | export * from './Navigator'; 3 | -------------------------------------------------------------------------------- /tlp-webapp/src/components/Layout/Navigator/NavigationLink/index.ts: -------------------------------------------------------------------------------- 1 | export { default } from './NavigationLink'; 2 | export * from './NavigationLink'; 3 | -------------------------------------------------------------------------------- /tlp-webapp/src/modules/widgets/index.ts: -------------------------------------------------------------------------------- 1 | export { default as WeeklyPerformance } from './WeeklyPerformance'; 2 | export * from './WeeklyPerformance'; 3 | -------------------------------------------------------------------------------- /tlp-webapp/public/images/characters/Anna.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcelherd/TekkenLearningPlatform/HEAD/tlp-webapp/public/images/characters/Anna.png -------------------------------------------------------------------------------- /tlp-webapp/public/images/characters/Bob.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcelherd/TekkenLearningPlatform/HEAD/tlp-webapp/public/images/characters/Bob.png -------------------------------------------------------------------------------- /tlp-webapp/public/images/characters/Eddy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcelherd/TekkenLearningPlatform/HEAD/tlp-webapp/public/images/characters/Eddy.png -------------------------------------------------------------------------------- /tlp-webapp/public/images/characters/Feng.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcelherd/TekkenLearningPlatform/HEAD/tlp-webapp/public/images/characters/Feng.png -------------------------------------------------------------------------------- /tlp-webapp/public/images/characters/Jin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcelherd/TekkenLearningPlatform/HEAD/tlp-webapp/public/images/characters/Jin.png -------------------------------------------------------------------------------- /tlp-webapp/public/images/characters/King.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcelherd/TekkenLearningPlatform/HEAD/tlp-webapp/public/images/characters/King.png -------------------------------------------------------------------------------- /tlp-webapp/public/images/characters/Kuma.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcelherd/TekkenLearningPlatform/HEAD/tlp-webapp/public/images/characters/Kuma.png -------------------------------------------------------------------------------- /tlp-webapp/public/images/characters/Lars.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcelherd/TekkenLearningPlatform/HEAD/tlp-webapp/public/images/characters/Lars.png -------------------------------------------------------------------------------- /tlp-webapp/public/images/characters/Law.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcelherd/TekkenLearningPlatform/HEAD/tlp-webapp/public/images/characters/Law.png -------------------------------------------------------------------------------- /tlp-webapp/public/images/characters/Lee.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcelherd/TekkenLearningPlatform/HEAD/tlp-webapp/public/images/characters/Lee.png -------------------------------------------------------------------------------- /tlp-webapp/public/images/characters/Lei.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcelherd/TekkenLearningPlatform/HEAD/tlp-webapp/public/images/characters/Lei.png -------------------------------------------------------------------------------- /tlp-webapp/public/images/characters/Leo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcelherd/TekkenLearningPlatform/HEAD/tlp-webapp/public/images/characters/Leo.png -------------------------------------------------------------------------------- /tlp-webapp/public/images/characters/Lili.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcelherd/TekkenLearningPlatform/HEAD/tlp-webapp/public/images/characters/Lili.png -------------------------------------------------------------------------------- /tlp-webapp/public/images/characters/Nina.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcelherd/TekkenLearningPlatform/HEAD/tlp-webapp/public/images/characters/Nina.png -------------------------------------------------------------------------------- /tlp-webapp/public/images/characters/Paul.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcelherd/TekkenLearningPlatform/HEAD/tlp-webapp/public/images/characters/Paul.png -------------------------------------------------------------------------------- /bin/start_all.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | cmd /C "set "NODE_ENV=production" && start tlp-recorder.exe" 3 | cmd /C "set "NODE_ENV=production" && start tlp-webapp.exe" 4 | -------------------------------------------------------------------------------- /tlp-webapp/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": true, 3 | "trailingComma": "all", 4 | "singleQuote": true, 5 | "printWidth": 100, 6 | "endOfLine": "auto" 7 | } 8 | -------------------------------------------------------------------------------- /tlp-webapp/public/images/characters/Akuma.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcelherd/TekkenLearningPlatform/HEAD/tlp-webapp/public/images/characters/Akuma.png -------------------------------------------------------------------------------- /tlp-webapp/public/images/characters/Alisa.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcelherd/TekkenLearningPlatform/HEAD/tlp-webapp/public/images/characters/Alisa.png -------------------------------------------------------------------------------- /tlp-webapp/public/images/characters/Asuka.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcelherd/TekkenLearningPlatform/HEAD/tlp-webapp/public/images/characters/Asuka.png -------------------------------------------------------------------------------- /tlp-webapp/public/images/characters/Bryan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcelherd/TekkenLearningPlatform/HEAD/tlp-webapp/public/images/characters/Bryan.png -------------------------------------------------------------------------------- /tlp-webapp/public/images/characters/Claudio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcelherd/TekkenLearningPlatform/HEAD/tlp-webapp/public/images/characters/Claudio.png -------------------------------------------------------------------------------- /tlp-webapp/public/images/characters/Eliza.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcelherd/TekkenLearningPlatform/HEAD/tlp-webapp/public/images/characters/Eliza.png -------------------------------------------------------------------------------- /tlp-webapp/public/images/characters/Ganryu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcelherd/TekkenLearningPlatform/HEAD/tlp-webapp/public/images/characters/Ganryu.png -------------------------------------------------------------------------------- /tlp-webapp/public/images/characters/Geese.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcelherd/TekkenLearningPlatform/HEAD/tlp-webapp/public/images/characters/Geese.png -------------------------------------------------------------------------------- /tlp-webapp/public/images/characters/Gigas.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcelherd/TekkenLearningPlatform/HEAD/tlp-webapp/public/images/characters/Gigas.png -------------------------------------------------------------------------------- /tlp-webapp/public/images/characters/Jack 7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcelherd/TekkenLearningPlatform/HEAD/tlp-webapp/public/images/characters/Jack 7.png -------------------------------------------------------------------------------- /tlp-webapp/public/images/characters/Josie.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcelherd/TekkenLearningPlatform/HEAD/tlp-webapp/public/images/characters/Josie.png -------------------------------------------------------------------------------- /tlp-webapp/public/images/characters/Julia.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcelherd/TekkenLearningPlatform/HEAD/tlp-webapp/public/images/characters/Julia.png -------------------------------------------------------------------------------- /tlp-webapp/public/images/characters/Kazumi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcelherd/TekkenLearningPlatform/HEAD/tlp-webapp/public/images/characters/Kazumi.png -------------------------------------------------------------------------------- /tlp-webapp/public/images/characters/Kazuya.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcelherd/TekkenLearningPlatform/HEAD/tlp-webapp/public/images/characters/Kazuya.png -------------------------------------------------------------------------------- /tlp-webapp/public/images/characters/Leroy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcelherd/TekkenLearningPlatform/HEAD/tlp-webapp/public/images/characters/Leroy.png -------------------------------------------------------------------------------- /tlp-webapp/public/images/characters/Lidia.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcelherd/TekkenLearningPlatform/HEAD/tlp-webapp/public/images/characters/Lidia.png -------------------------------------------------------------------------------- /tlp-webapp/public/images/characters/Marduk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcelherd/TekkenLearningPlatform/HEAD/tlp-webapp/public/images/characters/Marduk.png -------------------------------------------------------------------------------- /tlp-webapp/public/images/characters/Miguel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcelherd/TekkenLearningPlatform/HEAD/tlp-webapp/public/images/characters/Miguel.png -------------------------------------------------------------------------------- /tlp-webapp/public/images/characters/Negan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcelherd/TekkenLearningPlatform/HEAD/tlp-webapp/public/images/characters/Negan.png -------------------------------------------------------------------------------- /tlp-webapp/public/images/characters/Noctis.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcelherd/TekkenLearningPlatform/HEAD/tlp-webapp/public/images/characters/Noctis.png -------------------------------------------------------------------------------- /tlp-webapp/public/images/characters/Panda.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcelherd/TekkenLearningPlatform/HEAD/tlp-webapp/public/images/characters/Panda.png -------------------------------------------------------------------------------- /tlp-webapp/public/images/characters/Shaheen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcelherd/TekkenLearningPlatform/HEAD/tlp-webapp/public/images/characters/Shaheen.png -------------------------------------------------------------------------------- /tlp-webapp/public/images/characters/Steve.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcelherd/TekkenLearningPlatform/HEAD/tlp-webapp/public/images/characters/Steve.png -------------------------------------------------------------------------------- /tlp-webapp/public/images/characters/Xiaoyu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcelherd/TekkenLearningPlatform/HEAD/tlp-webapp/public/images/characters/Xiaoyu.png -------------------------------------------------------------------------------- /tlp-webapp/public/images/characters/Zafina.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcelherd/TekkenLearningPlatform/HEAD/tlp-webapp/public/images/characters/Zafina.png -------------------------------------------------------------------------------- /tlp-recorder/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": true, 3 | "trailingComma": "all", 4 | "singleQuote": true, 5 | "printWidth": 100, 6 | "endOfLine": "auto" 7 | } 8 | -------------------------------------------------------------------------------- /tlp-recorder/prisma/migrations/20220525200402_added_match_recorded/migration.sql: -------------------------------------------------------------------------------- 1 | -- AlterTable 2 | ALTER TABLE "Match" ADD COLUMN "recorded" BOOLEAN DEFAULT false; 3 | -------------------------------------------------------------------------------- /tlp-webapp/prisma/migrations/20220525200402_added_match_recorded/migration.sql: -------------------------------------------------------------------------------- 1 | -- AlterTable 2 | ALTER TABLE "Match" ADD COLUMN "recorded" BOOLEAN DEFAULT false; 3 | -------------------------------------------------------------------------------- /tlp-webapp/public/images/characters/Devil Jin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcelherd/TekkenLearningPlatform/HEAD/tlp-webapp/public/images/characters/Devil Jin.png -------------------------------------------------------------------------------- /tlp-webapp/public/images/characters/Dragunov.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcelherd/TekkenLearningPlatform/HEAD/tlp-webapp/public/images/characters/Dragunov.png -------------------------------------------------------------------------------- /tlp-webapp/public/images/characters/Fahkumram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcelherd/TekkenLearningPlatform/HEAD/tlp-webapp/public/images/characters/Fahkumram.png -------------------------------------------------------------------------------- /tlp-webapp/public/images/characters/Heihachi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcelherd/TekkenLearningPlatform/HEAD/tlp-webapp/public/images/characters/Heihachi.png -------------------------------------------------------------------------------- /tlp-webapp/public/images/characters/Hwoarang.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcelherd/TekkenLearningPlatform/HEAD/tlp-webapp/public/images/characters/Hwoarang.png -------------------------------------------------------------------------------- /tlp-webapp/public/images/characters/Katarina.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcelherd/TekkenLearningPlatform/HEAD/tlp-webapp/public/images/characters/Katarina.png -------------------------------------------------------------------------------- /tlp-webapp/public/images/characters/Kunimitsu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcelherd/TekkenLearningPlatform/HEAD/tlp-webapp/public/images/characters/Kunimitsu.png -------------------------------------------------------------------------------- /tlp-webapp/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | reactStrictMode: true, 4 | }; 5 | 6 | module.exports = nextConfig; 7 | -------------------------------------------------------------------------------- /tlp-webapp/public/images/characters/Armor King.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcelherd/TekkenLearningPlatform/HEAD/tlp-webapp/public/images/characters/Armor King.png -------------------------------------------------------------------------------- /tlp-webapp/public/images/characters/Lucky Chloe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcelherd/TekkenLearningPlatform/HEAD/tlp-webapp/public/images/characters/Lucky Chloe.png -------------------------------------------------------------------------------- /tlp-webapp/public/images/characters/Master Raven.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcelherd/TekkenLearningPlatform/HEAD/tlp-webapp/public/images/characters/Master Raven.png -------------------------------------------------------------------------------- /tlp-webapp/public/images/characters/Yoshimitsu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcelherd/TekkenLearningPlatform/HEAD/tlp-webapp/public/images/characters/Yoshimitsu.png -------------------------------------------------------------------------------- /tlp-webapp/prisma/migrations/migration_lock.toml: -------------------------------------------------------------------------------- 1 | # Please do not edit this file manually 2 | # It should be added in your version-control system (i.e. Git) 3 | provider = "sqlite" -------------------------------------------------------------------------------- /tlp-recorder/prisma/migrations/migration_lock.toml: -------------------------------------------------------------------------------- 1 | # Please do not edit this file manually 2 | # It should be added in your version-control system (i.e. Git) 3 | provider = "sqlite" -------------------------------------------------------------------------------- /tlp-webapp/next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | // NOTE: This file should not be edited 5 | // see https://nextjs.org/docs/basic-features/typescript for more information. 6 | -------------------------------------------------------------------------------- /tlp-webapp/src/modules/settings/index.ts: -------------------------------------------------------------------------------- 1 | export { default } from './SettingsForm'; 2 | export * from './SettingsForm'; 3 | 4 | export { default as useSettings } from './useSettings'; 5 | 6 | export { default as useSettingsForm } from './useSettingsForm'; 7 | -------------------------------------------------------------------------------- /tlp-webapp/src/components/common/PageTitle.tsx: -------------------------------------------------------------------------------- 1 | import { Title } from '@mantine/core'; 2 | 3 | export interface PageTitleProps { 4 | children: React.ReactNode; 5 | } 6 | 7 | export default function PageTitle({ children }: PageTitleProps) { 8 | return ( 9 | 10 | {children} 11 | 12 | ); 13 | } 14 | -------------------------------------------------------------------------------- /tlp-webapp/src/modules/rivals/index.ts: -------------------------------------------------------------------------------- 1 | export { default as RivalsTable } from './RivalsTable'; 2 | export * from './RivalsTable'; 3 | 4 | export { default as RivalsTableRow } from './RivalsTableRow'; 5 | export * from './RivalsTableRow'; 6 | 7 | export { default as useRival } from './useRival'; 8 | 9 | export { default as useRivals } from './useRivals'; 10 | -------------------------------------------------------------------------------- /tlp-webapp/src/pages/index.tsx: -------------------------------------------------------------------------------- 1 | import type { NextPage } from 'next'; 2 | 3 | const Home: NextPage = () => { 4 | return
Hello
; 5 | }; 6 | 7 | export function getServerSideProps() { 8 | return { 9 | redirect: { 10 | destination: '/dashboard', 11 | permanent: true, 12 | }, 13 | }; 14 | } 15 | 16 | export default Home; 17 | -------------------------------------------------------------------------------- /tlp-recorder/prisma/migrations/20220525115543_init/migration.sql: -------------------------------------------------------------------------------- 1 | -- CreateTable 2 | CREATE TABLE "Match" ( 3 | "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, 4 | "playerCharacter" TEXT NOT NULL, 5 | "opponent" TEXT NOT NULL, 6 | "opponentCharacter" TEXT NOT NULL, 7 | "stage" TEXT, 8 | "outcome" TEXT NOT NULL, 9 | "recordingUrl" TEXT 10 | ); 11 | -------------------------------------------------------------------------------- /tlp-webapp/prisma/migrations/20220525115543_init/migration.sql: -------------------------------------------------------------------------------- 1 | -- CreateTable 2 | CREATE TABLE "Match" ( 3 | "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, 4 | "playerCharacter" TEXT NOT NULL, 5 | "opponent" TEXT NOT NULL, 6 | "opponentCharacter" TEXT NOT NULL, 7 | "stage" TEXT, 8 | "outcome" TEXT NOT NULL, 9 | "recordingUrl" TEXT 10 | ); 11 | -------------------------------------------------------------------------------- /tlp-recorder/.env.sample: -------------------------------------------------------------------------------- 1 | ENABLE_DB_SYNC=true 2 | ENABLE_NOTATION_SYNC=false 3 | ENABLE_VIDEO_RECORD=false 4 | ENABLE_VIDEO_UPLOAD=false 5 | ENABLE_CLEANUP=true 6 | 7 | OBS_WS_PORT=4455 8 | OBS_WS_PASSWORD=changeme 9 | OBS_RECORD_PATH=C:/temp/TekkenLearningPlatform 10 | OBS_BATCH_SIZE=1 11 | OBS_UPLOAD_DELAY=500 12 | OBS_CLEANUP_DELAY=5000 13 | 14 | LOG_LEVEL=verbose 15 | TICK_INTERVAL=1 -------------------------------------------------------------------------------- /tlp-recorder/src/tekken/notation.ts: -------------------------------------------------------------------------------- 1 | import { InputData } from '@/types/types'; 2 | 3 | export default function getNotation(input: InputData) { 4 | const { direction, attack } = input; 5 | 6 | if (direction !== '' && direction !== 'n') { 7 | if (attack !== '') { 8 | return `${direction}+${attack}`; 9 | } 10 | return direction; 11 | } 12 | 13 | return attack; 14 | } 15 | -------------------------------------------------------------------------------- /tlp-webapp/src/modules/rivals/useRivals.ts: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | import { useQuery } from 'react-query'; 3 | 4 | import { Rival } from '@/lib/types'; 5 | 6 | async function findAll() { 7 | const { data } = await axios.get('/api/rivals'); 8 | return data; 9 | } 10 | 11 | export default function useRivals() { 12 | return useQuery('rivals', findAll); 13 | } 14 | -------------------------------------------------------------------------------- /tlp-webapp/src/components/common/BrandLogo.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Image from 'next/image'; 3 | 4 | import LogoSvg from '@/public/Logo.svg'; 5 | 6 | export interface BrandLogoProps { 7 | width?: number; 8 | } 9 | 10 | export default function BrandLogo({ width }: BrandLogoProps) { 11 | return Tekken Learning Platform Logo; 12 | } 13 | -------------------------------------------------------------------------------- /tlp-webapp/src/modules/settings/useSettings.ts: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | import { useQuery } from 'react-query'; 3 | 4 | import { Settings } from '@/lib/types'; 5 | 6 | async function fetchSettings() { 7 | const { data } = await axios.get('/api/settings'); 8 | return data; 9 | } 10 | 11 | export default function useSettings() { 12 | return useQuery('settings', fetchSettings); 13 | } 14 | -------------------------------------------------------------------------------- /tlp-webapp/src/modules/dashboard/useCharacters.ts: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | import { useQuery } from 'react-query'; 3 | 4 | import { Character } from '@/lib/types'; 5 | 6 | async function findAll() { 7 | const { data } = await axios.get('/api/characters'); 8 | return data; 9 | } 10 | 11 | export default function useCharacters() { 12 | return useQuery('characters', findAll); 13 | } 14 | -------------------------------------------------------------------------------- /tlp-recorder/jest.config.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from '@jest/types'; 2 | 3 | import { compilerOptions } from './tsconfig.json'; 4 | 5 | const config: Config.InitialOptions = { 6 | verbose: true, 7 | transform: { 8 | '^.+\\.tsx?$': 'ts-jest', 9 | }, 10 | modulePaths: [compilerOptions.baseUrl], 11 | moduleNameMapper: { 12 | '^@/(.*)$': '/src/$1', 13 | }, 14 | setupFilesAfterEnv: ['/jest.setup.ts'], 15 | }; 16 | 17 | export default config; 18 | -------------------------------------------------------------------------------- /tlp-webapp/src/modules/widgets/useWeeklyPerformance.tsx: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | import { useQuery } from 'react-query'; 3 | 4 | import { WeeklyPerformanceResponse } from '@/lib/types'; 5 | 6 | async function fetchData() { 7 | const { data } = await axios.get('/api/matches/weeklyPerformance'); 8 | return data; 9 | } 10 | 11 | export default function useWeeklyPerformance() { 12 | return useQuery(['weeklyPerformance'], fetchData); 13 | } 14 | -------------------------------------------------------------------------------- /tlp-webapp/src/pages/rivals/index.tsx: -------------------------------------------------------------------------------- 1 | import { Space, Text } from '@mantine/core'; 2 | 3 | import { NextPageWithLayout } from '@/lib/types'; 4 | import { RivalsTable } from '@/modules/rivals'; 5 | 6 | const Rivals: NextPageWithLayout = () => { 7 | return ( 8 | <> 9 | Showing your top 10 most played opponents. 10 | 11 | 12 | 13 | ); 14 | }; 15 | 16 | Rivals.pageTitle = 'Rivals'; 17 | 18 | export default Rivals; 19 | -------------------------------------------------------------------------------- /tlp-webapp/src/modules/matchHistory/useDeleteMatch.ts: -------------------------------------------------------------------------------- 1 | import { useRouter } from 'next/router'; 2 | 3 | import axios from 'axios'; 4 | import { useMutation } from 'react-query'; 5 | 6 | function deleteMatch(id: string | number) { 7 | return axios.delete(`/api/matches/${id}`); 8 | } 9 | 10 | export default function useDeleteMatch(id?: string | number) { 11 | const router = useRouter(); 12 | const matchId = id ?? (router.query.id as string); 13 | return useMutation(() => deleteMatch(matchId)); 14 | } 15 | -------------------------------------------------------------------------------- /tlp-webapp/src/modules/matchHistory/index.ts: -------------------------------------------------------------------------------- 1 | export { default as MatchesTable } from './MatchesTable'; 2 | export * from './MatchesTable'; 3 | 4 | export { default as MatchesTableRow } from './MatchesTableRow'; 5 | export * from './MatchesTableRow'; 6 | 7 | export { default as MatchVideo } from './MatchVideo'; 8 | export * from './MatchVideo'; 9 | 10 | export { default as useMatch } from './useMatch'; 11 | 12 | export { default as useMatches } from './useMatches'; 13 | 14 | export { default as useDeleteMatch } from './useDeleteMatch'; 15 | -------------------------------------------------------------------------------- /tlp-webapp/src/pages/_document.tsx: -------------------------------------------------------------------------------- 1 | import Document, { Head, Html, Main, NextScript } from 'next/document'; 2 | 3 | import { createGetInitialProps } from '@mantine/next'; 4 | 5 | const getInitialProps = createGetInitialProps(); 6 | 7 | export default class _Document extends Document { 8 | static getInitialProps = getInitialProps; 9 | 10 | render() { 11 | return ( 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | ); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /tlp-webapp/src/pages/history/index.tsx: -------------------------------------------------------------------------------- 1 | import { Space, Text } from '@mantine/core'; 2 | 3 | import { NextPageWithLayout } from '@/lib/types'; 4 | import { MatchesTable } from '@/modules/matchHistory'; 5 | 6 | const MatchHistory: NextPageWithLayout = () => { 7 | return ( 8 | <> 9 | Showing your latest 10 matches. Click on a match to get more information. 10 | 11 | 12 | 13 | ); 14 | }; 15 | 16 | MatchHistory.pageTitle = 'Match History'; 17 | 18 | export default MatchHistory; 19 | -------------------------------------------------------------------------------- /tlp-webapp/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | /pkg/ 3 | .env 4 | 5 | # dependencies 6 | /node_modules 7 | /.pnp 8 | .pnp.js 9 | 10 | # testing 11 | /coverage 12 | 13 | # next.js 14 | /.next/ 15 | /out/ 16 | 17 | # production 18 | /build 19 | 20 | # misc 21 | .DS_Store 22 | *.pem 23 | 24 | # debug 25 | npm-debug.log* 26 | yarn-debug.log* 27 | yarn-error.log* 28 | .pnpm-debug.log* 29 | 30 | # local env files 31 | .env*.local 32 | 33 | # vercel 34 | .vercel 35 | 36 | # typescript 37 | *.tsbuildinfo 38 | -------------------------------------------------------------------------------- /tlp-webapp/src/components/common/Breadcrumbs.tsx: -------------------------------------------------------------------------------- 1 | import { Anchor, Breadcrumbs as MantineBreadcrumbs } from '@mantine/core'; 2 | 3 | import { Breadcrumb } from '@/lib/types'; 4 | 5 | export interface BreadcrumbsProps { 6 | breadcrumbs: Breadcrumb[]; 7 | } 8 | 9 | export default function Breadcrumbs({ breadcrumbs }: BreadcrumbsProps) { 10 | const breadcrumbItems = breadcrumbs.map((item, index) => ( 11 | 12 | {item.label} 13 | 14 | )); 15 | 16 | return {breadcrumbItems}; 17 | } 18 | -------------------------------------------------------------------------------- /tlp-webapp/src/modules/matchHistory/useMatch.ts: -------------------------------------------------------------------------------- 1 | import { useRouter } from 'next/router'; 2 | 3 | import axios from 'axios'; 4 | import { useQuery } from 'react-query'; 5 | import { Match } from '@prisma/client'; 6 | 7 | async function findById(id: string | number) { 8 | const { data } = await axios.get(`/api/matches/${id}`); 9 | return data; 10 | } 11 | 12 | export default function useMatch(id?: string | number) { 13 | const router = useRouter(); 14 | const matchId = id ?? (router.query.id as string); 15 | return useQuery(['match', matchId], () => findById(matchId)); 16 | } 17 | -------------------------------------------------------------------------------- /tlp-webapp/src/components/common/Error.tsx: -------------------------------------------------------------------------------- 1 | import { Alert, Box } from '@mantine/core'; 2 | import { AlertTriangle } from 'tabler-icons-react'; 3 | 4 | export interface ErrorProps { 5 | error: Error; 6 | } 7 | 8 | export default function Error({ error }: ErrorProps) { 9 | return ( 10 | 11 | } 14 | variant="filled" 15 | title="Oops, something went wrong" 16 | color="red" 17 | > 18 | {error.name}: {error.message} 19 | 20 | 21 | ); 22 | } 23 | -------------------------------------------------------------------------------- /tlp-webapp/src/pages/dashboard/index.tsx: -------------------------------------------------------------------------------- 1 | import { Space, Text } from '@mantine/core'; 2 | 3 | import { NextPageWithLayout } from '@/lib/types'; 4 | import { CharactersTable } from '@/modules/dashboard'; 5 | import { WeeklyPerformance } from '@/modules/widgets/'; 6 | 7 | const Dashboard: NextPageWithLayout = () => { 8 | return ( 9 | <> 10 | Showing your played characters. 11 | 12 | 13 | 14 | 15 | 16 | ); 17 | }; 18 | 19 | Dashboard.pageTitle = 'Dashboard'; 20 | 21 | export default Dashboard; 22 | -------------------------------------------------------------------------------- /tlp-webapp/server.js: -------------------------------------------------------------------------------- 1 | const { createServer } = require('http'); 2 | const { parse } = require('url'); 3 | 4 | const next = require('next'); 5 | const conf = require('./next.config'); 6 | const open = require('open'); 7 | 8 | const app = next({ dev: false, conf, dir: __dirname }); 9 | const handle = app.getRequestHandler(); 10 | 11 | app.prepare().then(() => { 12 | createServer((req, res) => handle(req, res, parse(req.url, true).pathname)).listen( 13 | 3000, 14 | (err) => { 15 | if (err) throw err; 16 | console.log(`> Ready on http://localhost:3000`); 17 | open('http://localhost:3000'); 18 | }, 19 | ); 20 | }); 21 | -------------------------------------------------------------------------------- /tlp-webapp/src/modules/rivals/useRival.ts: -------------------------------------------------------------------------------- 1 | import { useRouter } from 'next/router'; 2 | 3 | import axios from 'axios'; 4 | import { useQuery } from 'react-query'; 5 | 6 | import { Rival } from '@/lib/types'; 7 | 8 | async function findById(id: string | number) { 9 | const { data } = await axios.get(`/api/rivals/${id}`); 10 | return data; 11 | } 12 | 13 | export default function useRival(id?: string | number) { 14 | const router = useRouter(); 15 | const rivalId = id ?? (router.query.id as string); // FIXME: this is "undefined" on the first render 16 | return useQuery(['rival', rivalId], () => findById(rivalId)); 17 | } 18 | -------------------------------------------------------------------------------- /tlp-webapp/src/modules/dashboard/useCharacterSummary.ts: -------------------------------------------------------------------------------- 1 | import { useRouter } from 'next/router'; 2 | 3 | import axios from 'axios'; 4 | import { useQuery } from 'react-query'; 5 | 6 | import { CharacterSummary } from '@/lib/types'; 7 | 8 | async function findByName(name: string) { 9 | const { data } = await axios.get(`/api/characters/${name}`); 10 | return data; 11 | } 12 | 13 | // TODO: Split this up 14 | export default function useCharacterSummary(characterName?: string) { 15 | const router = useRouter(); 16 | const name = characterName ?? (router.query.character as string); 17 | return useQuery(['character', name], () => findByName(name)); 18 | } 19 | -------------------------------------------------------------------------------- /tlp-webapp/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "forceConsistentCasingInFileNames": true, 9 | "noEmit": true, 10 | "esModuleInterop": true, 11 | "module": "esnext", 12 | "moduleResolution": "node", 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "jsx": "preserve", 16 | "incremental": true, 17 | "baseUrl": ".", 18 | "paths": { 19 | "@/*": ["./src/*"], 20 | "@/public/*": ["./public/*"] 21 | } 22 | }, 23 | "include": ["next-env.d.ts", "src/**/*.ts", "src/**/*.tsx"], 24 | "exclude": ["node_modules"] 25 | } 26 | -------------------------------------------------------------------------------- /tlp-webapp/src/pages/api/matches/index.ts: -------------------------------------------------------------------------------- 1 | import type { NextApiRequest, NextApiResponse } from 'next'; 2 | 3 | import { Match } from '@prisma/client'; 4 | 5 | import db from '@/lib/database'; 6 | 7 | export default async function handler( 8 | req: NextApiRequest, 9 | res: NextApiResponse 10 | ) { 11 | const limit = Number(req.query.limit); 12 | 13 | if (isNaN(limit)) { 14 | const matches = await db.match.findMany({ 15 | orderBy: { 16 | createdAt: 'desc', 17 | }, 18 | }); 19 | res.status(200).json(matches); 20 | } else { 21 | const matches = await db.match.findMany({ 22 | orderBy: { 23 | createdAt: 'desc', 24 | }, 25 | take: limit, 26 | }); 27 | res.status(200).json(matches); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /tlp-webapp/src/modules/matchHistory/useMatches.ts: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | import { useQuery } from 'react-query'; 3 | import { Match } from '@prisma/client'; 4 | 5 | import { CharacterSummary } from '@/lib/types'; 6 | 7 | async function findAll() { 8 | const { data } = await axios.get('/api/matches?limit=10'); 9 | return data; 10 | } 11 | 12 | async function findByCharacter(character: string) { 13 | const { data } = await axios.get(`/api/characters/${character}`); 14 | return data.latestMatches; 15 | } 16 | 17 | export default function useMatches(character?: string) { 18 | return useQuery(['matches', character], () => { 19 | if (character) { 20 | return findByCharacter(character); 21 | } 22 | return findAll(); 23 | }); 24 | } 25 | -------------------------------------------------------------------------------- /tlp-recorder/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "es2021": true, 5 | "jest": true 6 | }, 7 | "extends": ["airbnb-base", "airbnb-typescript/base", "plugin:jest/recommended", "prettier"], 8 | "parser": "@typescript-eslint/parser", 9 | "parserOptions": { 10 | "ecmaVersion": "latest", 11 | "sourceType": "module", 12 | "project": "./tsconfig.json" 13 | }, 14 | "plugins": ["@typescript-eslint", "jest", "prettier"], 15 | "ignorePatterns": ["temp.js", "dist/**/*"], 16 | "rules": { 17 | "prettier/prettier": "error", 18 | "no-plusplus": ["error", { "allowForLoopAfterthoughts": true }], 19 | "import/extensions": "off", 20 | "@typescript-eslint/no-unused-vars": ["warn"], 21 | "@typescript-eslint/lines-between-class-members": ["off"] 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /tlp-webapp/src/components/common/YoutubeEmbed.tsx: -------------------------------------------------------------------------------- 1 | import { Box } from '@mantine/core'; 2 | 3 | export interface YoutubeEmbedProps { 4 | href: string; 5 | title?: string; 6 | width?: string | number; 7 | height?: string | number; 8 | } 9 | 10 | export default function YoutubeEmbed({ href, title, width, height }: YoutubeEmbedProps) { 11 | const [baseUrl, videoId] = href.split('?v='); 12 | return ( 13 | 14 |