├── backend ├── .gitignore ├── package.json ├── src │ ├── index.ts │ └── outcomes.ts ├── tsconfig.json └── package-lock.json ├── frontend ├── src │ ├── components │ │ ├── ui │ │ │ ├── index.ts │ │ │ └── Button.tsx │ │ ├── index.ts │ │ ├── Quotes.tsx │ │ ├── Game.tsx │ │ ├── FoundIssue.tsx │ │ ├── Footer.tsx │ │ ├── Simulate.tsx │ │ ├── Simulation.tsx │ │ └── Navbar.tsx │ ├── vite-env.d.ts │ ├── utils │ │ └── index.ts │ ├── game │ │ ├── padding.ts │ │ ├── constants.ts │ │ ├── objects.ts │ │ ├── classes │ │ │ ├── Ball.ts │ │ │ └── BallManager.ts │ │ └── outcomes.ts │ ├── main.tsx │ ├── App.tsx │ ├── App.css │ ├── pages │ │ ├── Game.tsx │ │ ├── Simulation.tsx │ │ └── Home.tsx │ ├── index.css │ └── assets │ │ └── react.svg ├── postcss.config.js ├── vite.config.ts ├── tailwind.config.js ├── tsconfig.node.json ├── .gitignore ├── index.html ├── .eslintrc.cjs ├── tsconfig.json ├── package.json ├── README.md └── public │ └── vite.svg ├── version-1 └── index.html └── tsconfig.json /backend/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | -------------------------------------------------------------------------------- /frontend/src/components/ui/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./Button"; 2 | -------------------------------------------------------------------------------- /frontend/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /frontend/src/utils/index.ts: -------------------------------------------------------------------------------- 1 | export const baseURL = "http://localhost:3000"; 2 | -------------------------------------------------------------------------------- /frontend/postcss.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /frontend/src/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./Navbar"; 2 | export * from "./Quotes"; 3 | export * from "./Simulate"; 4 | export * from "./Footer"; 5 | export * from "./FoundIssue"; 6 | -------------------------------------------------------------------------------- /frontend/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }) 8 | -------------------------------------------------------------------------------- /frontend/tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | export default { 3 | content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"], 4 | theme: { 5 | extend: {}, 6 | }, 7 | plugins: [], 8 | }; 9 | -------------------------------------------------------------------------------- /frontend/src/game/padding.ts: -------------------------------------------------------------------------------- 1 | export const DECIMAL_MULTIPLIER = 10000; 2 | 3 | export function pad(n: number) { 4 | return n * DECIMAL_MULTIPLIER; 5 | } 6 | 7 | export function unpad(n: number) { 8 | return Math.floor(n / DECIMAL_MULTIPLIER); 9 | } 10 | -------------------------------------------------------------------------------- /frontend/src/main.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom/client' 3 | import App from './App.tsx' 4 | import './index.css' 5 | 6 | ReactDOM.createRoot(document.getElementById('root')!).render( 7 | 8 | 9 | , 10 | ) 11 | -------------------------------------------------------------------------------- /frontend/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "skipLibCheck": true, 5 | "module": "ESNext", 6 | "moduleResolution": "bundler", 7 | "allowSyntheticDefaultImports": true, 8 | "strict": true 9 | }, 10 | "include": ["vite.config.ts"] 11 | } 12 | -------------------------------------------------------------------------------- /frontend/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /frontend/src/game/constants.ts: -------------------------------------------------------------------------------- 1 | import { pad } from "./padding"; 2 | 3 | export const WIDTH = 800; 4 | export const HEIGHT = 800; 5 | export const ballRadius = 7; 6 | export const obstacleRadius = 4; 7 | 8 | export const gravity = pad(0.6); 9 | export const horizontalFriction = 0.4; 10 | export const verticalFriction = 0.8; 11 | 12 | export const sinkWidth = 36; 13 | export const NUM_SINKS = 17; 14 | -------------------------------------------------------------------------------- /frontend/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite + React + TS 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /frontend/src/components/ui/Button.tsx: -------------------------------------------------------------------------------- 1 | export const Button = ({ 2 | onClick, 3 | children, 4 | className, 5 | }: { 6 | onClick: () => void; 7 | children: React.ReactNode; 8 | className?: string; 9 | }) => { 10 | return ( 11 | 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /backend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "backend", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "build": "tsc -b", 8 | "start": "node dist/index.js" 9 | }, 10 | "keywords": [], 11 | "author": "", 12 | "license": "ISC", 13 | "dependencies": { 14 | "@types/cors": "^2.8.17", 15 | "@types/express": "^4.17.21", 16 | "cors": "^2.8.5", 17 | "express": "^4.19.2" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /frontend/.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { browser: true, es2020: true }, 4 | extends: [ 5 | 'eslint:recommended', 6 | 'plugin:@typescript-eslint/recommended', 7 | 'plugin:react-hooks/recommended', 8 | ], 9 | ignorePatterns: ['dist', '.eslintrc.cjs'], 10 | parser: '@typescript-eslint/parser', 11 | plugins: ['react-refresh'], 12 | rules: { 13 | 'react-refresh/only-export-components': [ 14 | 'warn', 15 | { allowConstantExport: true }, 16 | ], 17 | }, 18 | } 19 | -------------------------------------------------------------------------------- /frontend/src/App.tsx: -------------------------------------------------------------------------------- 1 | // import "./App.css"; 2 | import { BrowserRouter, Routes, Route } from "react-router-dom"; 3 | import { Simulation } from "./pages/Simulation"; 4 | import { Game } from "./pages/Game"; 5 | import { Footer, Navbar } from "./components"; 6 | import { Home } from "./pages/Home"; 7 | 8 | function App() { 9 | return ( 10 | 11 | 12 | 13 | } /> 14 | } /> 15 | } /> 16 | 17 |