TODO
\ No newline at end of file diff --git a/popup.js b/popup.js deleted file mode 100644 index 0ffdd02..0000000 --- a/popup.js +++ /dev/null @@ -1 +0,0 @@ -// TODO \ No newline at end of file diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 0000000..e99fa81 Binary files /dev/null and b/public/favicon.ico differ diff --git a/src/App.css b/src/App.css new file mode 100644 index 0000000..be887b6 --- /dev/null +++ b/src/App.css @@ -0,0 +1,129 @@ +.app { + width: 100vw; + height: 100vh; + overflow: hidden; + background-color: white; + position: relative; +} + +.stats { + position: fixed; + top: 20px; + left: 20px; + transform: none; + color: #213547; + background-color: white; + padding: 12px 20px; + border-radius: 8px; + font-family: Inter, system-ui, Arial, sans-serif; + font-size: 14px; + box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); + border: 1px solid #ddd; + z-index: 100; + display: flex; + gap: 12px; + align-items: center; +} + +.stats span { + white-space: nowrap; +} + +.container { + width: 100%; + height: 100%; + position: relative; + overflow: hidden; + cursor: crosshair; + touch-action: none; +} + +.content { + position: absolute; + width: 10000px; + /* Match VIRTUAL_CANVAS_SIZE */ + height: 10000px; + transform-origin: 0 0; + background-color: white; + background-image: linear-gradient(#ddd 1px, transparent 1px), + linear-gradient(90deg, #ddd 1px, transparent 1px); + background-size: 100px 100px; +} + +.target { + position: absolute; + background-color: #888888; + border-radius: 50%; + transition: background-color 0.2s ease; + box-shadow: 0 0 10px rgba(0, 0, 0, 0.2); + transform: translate(-50%, -50%); +} + +.target.active { + background-color: #44aa44; + box-shadow: 0 0 20px rgba(68, 170, 68, 0.4); +} + +html, +body, +#root { + margin: 0; + padding: 0; + width: 100%; + height: 100%; + overflow: hidden; + background-color: white; +} + +.controls { + position: fixed; + top: 20px; + right: 20px; + display: flex; + gap: 10px; + z-index: 1001; +} + +.settings-toggle, +.rounds-toggle, +.export-button, +.reset-button { + display: flex; + align-items: center; + gap: 6px; + background: white; + border: 1px solid #ddd; + padding: 8px 16px; + border-radius: 8px; + cursor: pointer; + font-size: 14px; + box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); + transition: all 0.2s ease; +} + +.settings-toggle:hover, +.rounds-toggle:hover, +.export-button:hover, +.reset-button:hover { + background: #f5f5f5; + border-color: #646cff; +} + +.export-button:disabled { + opacity: 0.5; + cursor: not-allowed; +} + +.export-button:disabled:hover { + background: white; + border-color: #ddd; +} + +.reset-button { + border-color: #ffcdd2; +} + +.reset-button:hover { + background: #fff5f5; + border-color: #ef5350; +} \ No newline at end of file diff --git a/src/App.tsx b/src/App.tsx new file mode 100644 index 0000000..f28b439 --- /dev/null +++ b/src/App.tsx @@ -0,0 +1,352 @@ +import React, { useState, useRef, useEffect } from 'react'; +import { Settings } from './components/Settings'; +import { RoundsHistory } from './components/RoundsHistory'; +import { Instructions } from './components/Instructions'; +import { saveState, loadState, exportToCSV } from './utils/storage'; +import { + Target, + Stats, + ViewportOffset, + AccelerationSettings, + Round, + CONSTANTS, +} from './types'; +import { generateTargets, getRandomTarget } from './utils/target'; +import { + calculateInitialViewport, + clampZoom, + calculateTouchDistance, + calculateZoomFactor +} from './utils/interaction'; +import { + createNewRound, + createInitialStats, + calculateAverageTime +} from './utils/stats'; +import { calculateAccelerationFactor, processWheelDelta, updateWheelSamples } from './utils/acceleration'; +import { createDefaultSettings } from './utils/settings'; +import { clamp } from './utils/math'; +import './App.css'; + +function App() { + // Core state + const [targets, setTargets] = useState+ This is a simulation that measures target acquisition performance with different zoom acceleration curves. +
+ ++ Try different acceleration curves to find what works best for you! +
+