Subh775 commited on
Commit
4d20521
·
1 Parent(s): 459069b

code refactored: high cohesion & low coupling..; seperation of concerns

Browse files
frontend/css/initial.css CHANGED
@@ -6,127 +6,65 @@
6
  --t2: #a89f97;
7
  --border: #2a2a2a;
8
  }
9
-
10
  body {
11
  font-family: 'Montserrat', sans-serif;
12
- background-color: #000000 !important;
13
  color: var(--t1);
14
- margin: 0;
15
- padding: 0;
16
  }
17
-
18
  .fade-in {
19
  animation: fadeIn 0.4s ease-in-out forwards;
20
  }
21
-
22
  @keyframes fadeIn {
23
  from {
24
  opacity: 0;
25
  transform: translateY(10px);
26
  }
27
-
28
  to {
29
  opacity: 1;
30
  transform: translateY(0);
31
  }
32
  }
33
-
34
- /* Executive Overrides for Pure Black Theme */
35
- .bg-black {
36
- background-color: #000000 !important;
37
- }
38
-
39
- .bg-neutral-950 {
40
- background-color: #050505 !important;
41
- }
42
-
43
- .bg-neutral-900 {
44
- background-color: #0a0a0a !important;
45
- }
46
-
47
- .text-white {
48
- color: #f0ece6 !important;
49
- }
50
-
51
  .traffic-dynamics-card {
52
- background-color: #050505 !important;
53
  border: 2px solid var(--cocoa) !important;
54
- transition: all 0.3s ease;
55
  }
56
-
57
  .traffic-dynamics-card:hover {
58
  border-color: var(--cocoa-l) !important;
59
- transform: translateY(-4px);
60
- box-shadow: 0 10px 30px rgba(0,0,0,0.5);
61
  }
62
-
63
  #dropzone {
64
  transition: all 0.2s ease;
65
- border-color: #2a2a2a !important;
66
- background-color: #020202 !important;
67
  }
68
-
69
  #dropzone:hover {
70
  border-color: var(--cocoa-l) !important;
71
- background-color: #050505 !important;
72
  }
73
-
74
  .core-badge {
75
  background-color: var(--cocoa) !important;
76
- color: #000 !important;
77
- font-weight: 800;
78
  }
79
-
80
  /* Onboarding */
81
  .onboard-overlay {
82
  position: fixed; inset: 0; z-index: 9999;
83
- background: rgba(0,0,0,0.95);
84
  display: flex; align-items: center; justify-content: center;
85
- backdrop-filter: blur(4px);
86
  }
87
-
88
  .onboard-card {
89
- background: #050505; border: 1px solid #2a2a2a;
90
- border-radius: 20px; max-width: 440px; width: 90%;
91
  padding: 40px 32px; text-align: center;
92
- box-shadow: 0 20px 50px rgba(0,0,0,0.8);
93
  }
94
-
95
  .onboard-step { display: none; }
96
  .onboard-step.active { display: block; }
97
-
98
- .onboard-dots { display: flex; gap: 8px; justify-content: center; margin-top: 24px; }
99
  .onboard-dot {
100
- width: 6px; height: 6px; border-radius: 50%;
101
- background: #222; transition: all 0.3s ease;
102
- }
103
- .onboard-dot.active {
104
- background: var(--cocoa-l);
105
- transform: scale(1.3);
106
- }
107
-
108
- #btn-proceed {
109
- background-color: #c89a6c !important;
110
- color: #000000 !important;
111
- border: none !important;
112
- box-shadow: 0 4px 15px rgba(200, 154, 108, 0.3) !important;
113
- transition: all 0.3s ease !important;
114
  }
115
-
116
- #btn-proceed:hover {
117
- background-color: #d4b08a !important;
118
- transform: scale(1.05) translateY(-2px) !important;
119
- box-shadow: 0 8px 25px rgba(200, 154, 108, 0.4) !important;
120
- }
121
-
122
- #upload-bar {
123
- background-color: #c89a6c !important;
124
- }
125
-
126
  /* Mobile responsive */
127
  @media (max-width: 768px) {
128
- main { grid-template-columns: 1fr !important; padding: 24px 16px !important; }
129
- h1 { font-size: 2.5rem !important; line-height: 1.2 !important; }
130
- header { mt-8 !important; }
131
- }
132
-
 
6
  --t2: #a89f97;
7
  --border: #2a2a2a;
8
  }
 
9
  body {
10
  font-family: 'Montserrat', sans-serif;
11
+ background-color: #000000;
12
  color: var(--t1);
 
 
13
  }
 
14
  .fade-in {
15
  animation: fadeIn 0.4s ease-in-out forwards;
16
  }
 
17
  @keyframes fadeIn {
18
  from {
19
  opacity: 0;
20
  transform: translateY(10px);
21
  }
 
22
  to {
23
  opacity: 1;
24
  transform: translateY(0);
25
  }
26
  }
27
+ /* Executive Overrides */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
  .traffic-dynamics-card {
29
+ background-color: #0a0a0a !important;
30
  border: 2px solid var(--cocoa) !important;
 
31
  }
 
32
  .traffic-dynamics-card:hover {
33
  border-color: var(--cocoa-l) !important;
 
 
34
  }
 
35
  #dropzone {
36
  transition: all 0.2s ease;
37
+ border-color: #2a2a2a;
 
38
  }
 
39
  #dropzone:hover {
40
  border-color: var(--cocoa-l) !important;
41
+ background-color: #0a0a0a !important;
42
  }
 
43
  .core-badge {
44
  background-color: var(--cocoa) !important;
45
+ color: var(--t1) !important;
 
46
  }
 
47
  /* Onboarding */
48
  .onboard-overlay {
49
  position: fixed; inset: 0; z-index: 9999;
50
+ background: rgba(0,0,0,0.92);
51
  display: flex; align-items: center; justify-content: center;
 
52
  }
 
53
  .onboard-card {
54
+ background: #0a0a0a; border: 1px solid #2a2a2a;
55
+ border-radius: 16px; max-width: 440px; width: 90%;
56
  padding: 40px 32px; text-align: center;
 
57
  }
 
58
  .onboard-step { display: none; }
59
  .onboard-step.active { display: block; }
60
+ .onboard-dots { display: flex; gap: 6px; justify-content: center; margin-top: 20px; }
 
61
  .onboard-dot {
62
+ width: 8px; height: 8px; border-radius: 50%;
63
+ background: #333; transition: background 0.2s;
 
 
 
 
 
 
 
 
 
 
 
 
64
  }
65
+ .onboard-dot.active { background: var(--cocoa-l); }
 
 
 
 
 
 
 
 
 
 
66
  /* Mobile responsive */
67
  @media (max-width: 768px) {
68
+ main { grid-template-columns: 1fr !important; padding: 16px !important; }
69
+ h1 { font-size: 2.2rem !important; }
70
+ }
 
 
frontend/initial.html CHANGED
@@ -18,27 +18,24 @@
18
  <meta charset="UTF-8">
19
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
20
  <title>UrbanFlow</title>
21
- <link rel="icon" type="image/svg+xml" href="/assets/rf.png">
22
  <script src="https://cdn.tailwindcss.com"></script>
23
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
24
- <link
25
- href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Montserrat:wght@400;500;600;700;800;900&display=swap"
26
- rel="stylesheet">
27
  <link rel="stylesheet" href="/css/initial.css">
28
  </head>
29
 
30
- <body
31
- class="bg-black text-white min-h-screen w-full flex flex-col items-center selection:bg-white selection:text-black">
32
 
33
  <header class="mt-16 flex flex-col items-center flex-shrink-0 w-full z-10">
34
  <img src="/assets/uf_rf.png" alt="UrbanFlow Logo" class="h-44 md:h-52 w-auto object-contain mb-3">
35
  </header>
36
 
37
- <main
38
- class="flex-1 w-full max-w-[90rem] mx-auto grid grid-cols-1 lg:grid-cols-12 gap-12 lg:gap-20 px-10 py-6 items-center z-10">
39
 
40
  <div class="lg:col-span-7 flex flex-col justify-center xl:pl-10 pb-10 lg:pb-0">
41
- <h1 class="text-5xl xl:text-[4.5rem] font-extrabold mb-4 leading-[1.1] tracking-tight" style="background:linear-gradient(110deg,#f0ece6 0%,#f0ece6 35%,#c89a6c 100%);-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text">
 
42
  Automated <br>Vision Intelligence
43
  </h1>
44
  <p class="font-bold mb-8 text-sm uppercase tracking-[0.2em] flex items-center" style="color:#a89f97">
@@ -54,21 +51,17 @@
54
  </ul>
55
  </div>
56
 
57
- <div
58
- class="lg:col-span-5 flex flex-col justify-center w-full max-w-[32rem] mx-auto min-h-[450px] mb-12 lg:mb-0">
59
 
60
  <!-- STEP: Modules -->
61
  <div id="step-modules" class="w-full flex flex-col fade-in">
62
  <h2 class="text-3xl font-bold mb-2 text-center" style="color:#f0ece6">UrbanFlow</h2>
63
  <p class="text-[13px] font-medium mb-8 text-center" style="color:#a89f97">Select an analytical module to continue.</p>
64
-
65
  <div class="flex justify-center w-full">
66
  <div onclick="showStep('upload')"
67
  class="group relative border-2 rounded-[2rem] p-8 cursor-pointer hover:-translate-y-1 transition-all duration-300 text-center max-w-sm w-full traffic-dynamics-card">
68
- <div
69
- class="absolute top-4 right-6 text-[9px] font-bold px-2.5 py-1 rounded-full uppercase tracking-wider"
70
- style="background:#c89a6c;color:#000">
71
- DEMO</div>
72
  <i class="fa-solid fa-car-side text-4xl mb-4 block mx-auto" style="color:#c89a6c"></i>
73
  <h3 class="font-bold text-lg mb-2 leading-tight" style="color:#f0ece6">Traffic <br>Dynamics</h3>
74
  <p class="text-[10px] font-medium leading-relaxed" style="color:#a89f97">Vehicle counting, classification, and flow analysis for Indian roads.</p>
@@ -80,28 +73,24 @@
80
  <div id="step-upload" class="hidden w-full flex flex-col fade-in">
81
  <button onclick="showStep('modules')"
82
  class="text-neutral-500 hover:text-white transition flex items-center text-xs font-bold uppercase tracking-widest mb-6 w-fit">
83
- <i class="fa-solid fa-arrow-left mr-2"></i> Back
84
  </button>
85
  <h2 class="text-3xl font-bold mb-2 text-center" style="color:#f0ece6">Source Media</h2>
86
  <p class="text-[13px] font-medium mb-8 text-center" style="color:#a89f97">Submit camera footage to begin traffic analysis.</p>
87
-
88
  <input id="file-input" type="file" accept="video/*" class="hidden">
89
  <div id="dropzone" onclick="document.getElementById('file-input').click()"
90
  class="border border-dashed border-neutral-700 rounded-[2rem] p-12 flex flex-col items-center justify-center cursor-pointer transition-all duration-300 group">
91
- <i
92
- class="fa-solid fa-arrow-up-from-bracket text-4xl mb-5 block mx-auto transition" style="color:#a89f97"></i>
93
  <span class="font-semibold text-lg mb-2 text-center block" style="color:#f0ece6">Drop or select a video file</span>
94
  <span class="text-[10px] font-bold uppercase tracking-widest text-center block" style="color:#a89f97">Any standard video format accepted</span>
95
  </div>
96
-
97
  <div id="upload-progress-container" class="hidden mt-10 w-full">
98
  <div class="flex justify-between text-[11px] font-bold uppercase tracking-widest mb-3" style="color:#f0ece6">
99
  <span id="upload-text">Uploading...</span>
100
  <span id="upload-percentage">0%</span>
101
  </div>
102
  <div class="w-full h-1 bg-neutral-900 rounded-full overflow-hidden">
103
- <div id="upload-bar"
104
- class="h-full w-0 transition-all duration-75 ease-linear rounded-full" style="background:#c89a6c"></div>
105
  </div>
106
  </div>
107
  </div>
@@ -110,26 +99,24 @@
110
  <div id="step-draw" class="hidden w-full flex flex-col fade-in">
111
  <h2 class="text-3xl font-bold mb-2 text-center" style="color:#f0ece6">Spatial Boundary</h2>
112
  <p class="text-[11px] font-bold uppercase tracking-widest mb-6 text-center" style="color:#a89f97">Mark two points to define the vehicle counting threshold</p>
113
-
114
- <div
115
- class="relative w-full aspect-video bg-neutral-950 rounded-3xl overflow-hidden cursor-crosshair mb-6">
116
  <img id="frame-img" class="absolute inset-0 w-full h-full object-contain" style="display:none;">
117
  <div id="frame-placeholder"
118
  class="absolute inset-0 flex flex-col items-center justify-center text-neutral-800 pointer-events-none">
119
  <i class="fa-solid fa-video text-4xl mb-3 opacity-30"></i>
120
- <span class="font-bold text-[10px] uppercase tracking-widest opacity-50">Media Frame
121
- Preview</span>
122
  </div>
123
  <canvas id="drawing-canvas" class="absolute inset-0 w-full h-full"></canvas>
124
  </div>
125
-
126
  <div class="flex flex-col items-center gap-3">
127
  <button id="btn-proceed" onclick="startRun()"
128
- class="w-fit px-16 py-3.5 rounded-full font-bold text-center text-sm shadow-lg">
 
129
  Continue &nbsp;&rarr;
130
  </button>
131
  <button onclick="resetCanvas()"
132
- class="text-[10px] font-bold uppercase tracking-widest text-slate-500 hover:text-white transition" style="background:none;border:none;">Reset Boundary</button>
 
133
  </div>
134
  </div>
135
 
@@ -144,7 +131,7 @@
144
  <div class="onboard-step active" data-step="0">
145
  <i class="fa-solid fa-cloud-arrow-up text-4xl mb-4" style="color:var(--cocoa-l)"></i>
146
  <h3 class="text-lg font-bold mb-2" style="color:#f0ece6">Upload a Traffic Video</h3>
147
- <p class="text-xs" style="color:#777;line-height:1.7">Drag & drop or select a video file recorded from any traffic camera. MP4, MOV, AVI formats supported.</p>
148
  </div>
149
  <div class="onboard-step" data-step="1">
150
  <i class="fa-solid fa-draw-polygon text-4xl mb-4" style="color:var(--cocoa-l)"></i>
@@ -153,7 +140,7 @@
153
  </div>
154
  <div class="onboard-step" data-step="2">
155
  <i class="fa-solid fa-chart-line text-4xl mb-4" style="color:var(--cocoa-l)"></i>
156
- <h3 class="text-lg font-bold mb-2" style="color:#f0ece6">Review Analytics & Export</h3>
157
  <p class="text-xs" style="color:#777;line-height:1.7">Watch real-time charts populate as inference runs. Download annotated video, reports, and structured JSON when complete.</p>
158
  </div>
159
  <div class="onboard-dots">
@@ -162,12 +149,15 @@
162
  <span class="onboard-dot"></span>
163
  </div>
164
  <div class="flex gap-3 justify-center mt-6">
165
- <button onclick="closeOnboarding()" class="text-[10px] font-bold uppercase tracking-widest px-4 py-2 rounded-full" style="color:#555;border:1px solid #222">Skip</button>
166
- <button id="onboard-next" onclick="nextOnboardStep()" class="text-[10px] font-bold uppercase tracking-widest px-6 py-2 rounded-full" style="background:var(--cocoa);color:#f0ece6">Next</button>
 
 
 
 
167
  </div>
168
  </div>
169
  </div>
170
 
171
  </body>
172
-
173
  </html>
 
18
  <meta charset="UTF-8">
19
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
20
  <title>UrbanFlow</title>
21
+ <link rel="icon" type="image/png" href="/assets/rf.png">
22
  <script src="https://cdn.tailwindcss.com"></script>
23
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
24
+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Montserrat:wght@400;500;600;700;800;900&display=swap" rel="stylesheet">
 
 
25
  <link rel="stylesheet" href="/css/initial.css">
26
  </head>
27
 
28
+ <body class="bg-black text-white min-h-screen w-full flex flex-col items-center selection:bg-white selection:text-black">
 
29
 
30
  <header class="mt-16 flex flex-col items-center flex-shrink-0 w-full z-10">
31
  <img src="/assets/uf_rf.png" alt="UrbanFlow Logo" class="h-44 md:h-52 w-auto object-contain mb-3">
32
  </header>
33
 
34
+ <main class="flex-1 w-full max-w-[90rem] mx-auto grid grid-cols-1 lg:grid-cols-12 gap-12 lg:gap-20 px-10 py-6 items-center z-10">
 
35
 
36
  <div class="lg:col-span-7 flex flex-col justify-center xl:pl-10 pb-10 lg:pb-0">
37
+ <h1 class="text-5xl xl:text-[4.5rem] font-extrabold mb-4 leading-[1.1] tracking-tight"
38
+ style="background:linear-gradient(110deg,#f0ece6 0%,#f0ece6 35%,#c89a6c 100%);-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text">
39
  Automated <br>Vision Intelligence
40
  </h1>
41
  <p class="font-bold mb-8 text-sm uppercase tracking-[0.2em] flex items-center" style="color:#a89f97">
 
51
  </ul>
52
  </div>
53
 
54
+ <div class="lg:col-span-5 flex flex-col justify-center w-full max-w-[32rem] mx-auto min-h-[450px] mb-12 lg:mb-0">
 
55
 
56
  <!-- STEP: Modules -->
57
  <div id="step-modules" class="w-full flex flex-col fade-in">
58
  <h2 class="text-3xl font-bold mb-2 text-center" style="color:#f0ece6">UrbanFlow</h2>
59
  <p class="text-[13px] font-medium mb-8 text-center" style="color:#a89f97">Select an analytical module to continue.</p>
 
60
  <div class="flex justify-center w-full">
61
  <div onclick="showStep('upload')"
62
  class="group relative border-2 rounded-[2rem] p-8 cursor-pointer hover:-translate-y-1 transition-all duration-300 text-center max-w-sm w-full traffic-dynamics-card">
63
+ <div class="absolute top-4 right-6 text-[9px] font-bold px-2.5 py-1 rounded-full uppercase tracking-wider"
64
+ style="background:#c89a6c;color:#000">DEMO</div>
 
 
65
  <i class="fa-solid fa-car-side text-4xl mb-4 block mx-auto" style="color:#c89a6c"></i>
66
  <h3 class="font-bold text-lg mb-2 leading-tight" style="color:#f0ece6">Traffic <br>Dynamics</h3>
67
  <p class="text-[10px] font-medium leading-relaxed" style="color:#a89f97">Vehicle counting, classification, and flow analysis for Indian roads.</p>
 
73
  <div id="step-upload" class="hidden w-full flex flex-col fade-in">
74
  <button onclick="showStep('modules')"
75
  class="text-neutral-500 hover:text-white transition flex items-center text-xs font-bold uppercase tracking-widest mb-6 w-fit">
76
+ <i class="fa-solid fa-arrow-left mr-2"></i> Back
77
  </button>
78
  <h2 class="text-3xl font-bold mb-2 text-center" style="color:#f0ece6">Source Media</h2>
79
  <p class="text-[13px] font-medium mb-8 text-center" style="color:#a89f97">Submit camera footage to begin traffic analysis.</p>
 
80
  <input id="file-input" type="file" accept="video/*" class="hidden">
81
  <div id="dropzone" onclick="document.getElementById('file-input').click()"
82
  class="border border-dashed border-neutral-700 rounded-[2rem] p-12 flex flex-col items-center justify-center cursor-pointer transition-all duration-300 group">
83
+ <i class="fa-solid fa-arrow-up-from-bracket text-4xl mb-5 block mx-auto transition" style="color:#a89f97"></i>
 
84
  <span class="font-semibold text-lg mb-2 text-center block" style="color:#f0ece6">Drop or select a video file</span>
85
  <span class="text-[10px] font-bold uppercase tracking-widest text-center block" style="color:#a89f97">Any standard video format accepted</span>
86
  </div>
 
87
  <div id="upload-progress-container" class="hidden mt-10 w-full">
88
  <div class="flex justify-between text-[11px] font-bold uppercase tracking-widest mb-3" style="color:#f0ece6">
89
  <span id="upload-text">Uploading...</span>
90
  <span id="upload-percentage">0%</span>
91
  </div>
92
  <div class="w-full h-1 bg-neutral-900 rounded-full overflow-hidden">
93
+ <div id="upload-bar" class="h-full w-0 transition-all duration-75 ease-linear rounded-full" style="background:#c89a6c"></div>
 
94
  </div>
95
  </div>
96
  </div>
 
99
  <div id="step-draw" class="hidden w-full flex flex-col fade-in">
100
  <h2 class="text-3xl font-bold mb-2 text-center" style="color:#f0ece6">Spatial Boundary</h2>
101
  <p class="text-[11px] font-bold uppercase tracking-widest mb-6 text-center" style="color:#a89f97">Mark two points to define the vehicle counting threshold</p>
102
+ <div class="relative w-full aspect-video bg-neutral-950 rounded-3xl overflow-hidden cursor-crosshair mb-6">
 
 
103
  <img id="frame-img" class="absolute inset-0 w-full h-full object-contain" style="display:none;">
104
  <div id="frame-placeholder"
105
  class="absolute inset-0 flex flex-col items-center justify-center text-neutral-800 pointer-events-none">
106
  <i class="fa-solid fa-video text-4xl mb-3 opacity-30"></i>
107
+ <span class="font-bold text-[10px] uppercase tracking-widest opacity-50">Media Frame Preview</span>
 
108
  </div>
109
  <canvas id="drawing-canvas" class="absolute inset-0 w-full h-full"></canvas>
110
  </div>
 
111
  <div class="flex flex-col items-center gap-3">
112
  <button id="btn-proceed" onclick="startRun()"
113
+ class="w-fit px-16 py-3.5 rounded-full font-bold transition-all text-center text-sm shadow-lg hover:scale-105 active:scale-95"
114
+ style="background:#c89a6c;color:#000">
115
  Continue &nbsp;&rarr;
116
  </button>
117
  <button onclick="resetCanvas()"
118
+ class="text-[10px] font-bold uppercase tracking-widest text-slate-500 hover:text-white transition"
119
+ style="background:none;border:none;">Reset Boundary</button>
120
  </div>
121
  </div>
122
 
 
131
  <div class="onboard-step active" data-step="0">
132
  <i class="fa-solid fa-cloud-arrow-up text-4xl mb-4" style="color:var(--cocoa-l)"></i>
133
  <h3 class="text-lg font-bold mb-2" style="color:#f0ece6">Upload a Traffic Video</h3>
134
+ <p class="text-xs" style="color:#777;line-height:1.7">Drag &amp; drop or select a video file recorded from any traffic camera. MP4, MOV, AVI formats supported.</p>
135
  </div>
136
  <div class="onboard-step" data-step="1">
137
  <i class="fa-solid fa-draw-polygon text-4xl mb-4" style="color:var(--cocoa-l)"></i>
 
140
  </div>
141
  <div class="onboard-step" data-step="2">
142
  <i class="fa-solid fa-chart-line text-4xl mb-4" style="color:var(--cocoa-l)"></i>
143
+ <h3 class="text-lg font-bold mb-2" style="color:#f0ece6">Review Analytics &amp; Export</h3>
144
  <p class="text-xs" style="color:#777;line-height:1.7">Watch real-time charts populate as inference runs. Download annotated video, reports, and structured JSON when complete.</p>
145
  </div>
146
  <div class="onboard-dots">
 
149
  <span class="onboard-dot"></span>
150
  </div>
151
  <div class="flex gap-3 justify-center mt-6">
152
+ <button onclick="closeOnboarding()"
153
+ class="text-[10px] font-bold uppercase tracking-widest px-4 py-2 rounded-full"
154
+ style="color:#555;border:1px solid #222">Skip</button>
155
+ <button id="onboard-next" onclick="nextOnboardStep()"
156
+ class="text-[10px] font-bold uppercase tracking-widest px-6 py-2 rounded-full"
157
+ style="background:var(--cocoa);color:#f0ece6">Next</button>
158
  </div>
159
  </div>
160
  </div>
161
 
162
  </body>
 
163
  </html>
frontend/js/initial.js CHANGED
@@ -12,7 +12,6 @@ function showStep(name) {
12
  if (name === 'upload') {
13
  document.getElementById('upload-progress-container').classList.add('hidden');
14
  document.getElementById('dropzone').classList.remove('hidden');
15
- // Reset Progress Bar state for new uploads
16
  document.getElementById('upload-bar').style.width = '0%';
17
  document.getElementById('upload-percentage').innerText = '0%';
18
  document.getElementById('upload-text').innerText = 'Uploading...';
@@ -31,8 +30,13 @@ if (fileInput) {
31
  }
32
 
33
  if (dropzone) {
34
- dropzone.addEventListener('dragover', e => { e.preventDefault(); dropzone.classList.add('border-white', 'bg-neutral-950'); });
35
- dropzone.addEventListener('dragleave', () => dropzone.classList.remove('border-white', 'bg-neutral-950'));
 
 
 
 
 
36
  dropzone.addEventListener('drop', e => {
37
  e.preventDefault();
38
  dropzone.classList.remove('border-white', 'bg-neutral-950');
@@ -41,18 +45,18 @@ if (dropzone) {
41
  }
42
 
43
  let currentXHR = null;
 
44
  function uploadFile(file) {
45
- // Abort previous upload if it exists to prevent jitter/multiple requests
46
  if (currentXHR) currentXHR.abort();
47
 
48
  const dropzoneEl = document.getElementById('dropzone');
49
- const prog = document.getElementById('upload-progress-container');
50
- const bar = document.getElementById('upload-bar');
51
- const pct = document.getElementById('upload-percentage');
52
- const txt = document.getElementById('upload-text');
53
 
54
  if (dropzoneEl) dropzoneEl.classList.add('hidden');
55
- if (prog) prog.classList.remove('hidden');
56
 
57
  const form = new FormData();
58
  form.append('file', file);
@@ -93,33 +97,36 @@ function uploadFile(file) {
93
  .then(cfg => {
94
  runConfig = cfg;
95
  runConfig.conf = 0.12;
96
- runConfig.iou = 0.60;
97
  txt.innerText = 'Initialization Complete';
98
  fileInput.value = '';
99
  setTimeout(() => showStep('draw'), 800);
100
  })
101
- .catch(e => {
102
  txt.innerText = 'Metadata Failed';
103
  txt.classList.add('text-red-500');
104
  fileInput.value = '';
105
  });
106
  };
 
107
  xhr.send(form);
108
  }
109
 
110
- // Draw Canvas Logic
111
  const canvas = document.getElementById('drawing-canvas');
112
- const ctx = canvas.getContext('2d');
113
- let points = [];
114
- let imgNatW = 0, imgNatH = 0;
115
 
116
  function loadFirstFrame() {
117
- const img = document.getElementById('frame-img');
118
  const placeholder = document.getElementById('frame-placeholder');
119
-
120
  img.onerror = () => {
121
  console.error('Failed to load first frame');
122
- placeholder.innerHTML = '<i class="fa-solid fa-circle-exclamation text-4xl mb-3 text-red-500 opacity-50"></i><span class="font-bold text-[10px] uppercase tracking-widest opacity-50">Frame Load Error</span>';
 
 
123
  };
124
 
125
  img.src = '/first-frame/' + videoId;
@@ -127,14 +134,14 @@ function loadFirstFrame() {
127
  imgNatW = img.naturalWidth;
128
  imgNatH = img.naturalHeight;
129
  img.style.display = 'block';
130
- placeholder.style.display = 'none';
131
  initCanvas();
132
  };
133
  }
134
 
135
  function initCanvas() {
136
  if (canvas) {
137
- canvas.width = canvas.offsetWidth;
138
  canvas.height = canvas.offsetHeight;
139
  }
140
  }
@@ -145,10 +152,10 @@ if (canvas) {
145
  canvas.addEventListener('mousedown', e => {
146
  if (points.length >= 2) return;
147
  const rect = canvas.getBoundingClientRect();
148
- const cx = e.clientX - rect.left;
149
- const cy = e.clientY - rect.top;
150
- const rx = (cx / canvas.width) * imgNatW;
151
- const ry = (cy / canvas.height) * imgNatH;
152
  points.push({ cx, cy, rx: Math.round(rx), ry: Math.round(ry) });
153
  drawDot(cx, cy);
154
  if (points.length === 2) drawLine();
@@ -158,10 +165,10 @@ if (canvas) {
158
  function drawDot(x, y) {
159
  ctx.beginPath();
160
  ctx.arc(x, y, 5, 0, Math.PI * 2);
161
- ctx.fillStyle = '#c89a6c';
162
  ctx.fill();
163
  ctx.strokeStyle = '#f0ece6';
164
- ctx.lineWidth = 2;
165
  ctx.stroke();
166
  }
167
 
@@ -170,13 +177,13 @@ function drawLine() {
170
  ctx.moveTo(points[0].cx, points[0].cy);
171
  ctx.lineTo(points[1].cx, points[1].cy);
172
  ctx.strokeStyle = '#c89a6c';
173
- ctx.lineWidth = 3;
174
  ctx.stroke();
175
  }
176
 
177
  function resetCanvas() {
178
  points = [];
179
- ctx.clearRect(0, 0, canvas.width, canvas.height);
180
  }
181
 
182
  function startRun() {
@@ -184,25 +191,29 @@ function startRun() {
184
  const line = [[points[0].rx, points[0].ry], [points[1].rx, points[1].ry]];
185
  sessionStorage.setItem('funky_run', JSON.stringify({
186
  video_id: videoId,
187
- line: line,
188
- config: runConfig
189
  }));
190
  window.location.href = '/';
191
  }
192
 
 
193
  let _obStep = 0;
 
194
  function nextOnboardStep() {
195
  _obStep++;
196
  if (_obStep >= 3) { closeOnboarding(); return; }
197
  document.querySelectorAll('.onboard-step').forEach((s, i) => s.classList.toggle('active', i === _obStep));
198
- document.querySelectorAll('.onboard-dot').forEach((d, i) => d.classList.toggle('active', i === _obStep));
199
  if (_obStep === 2) document.getElementById('onboard-next').innerText = 'Get Started';
200
  }
 
201
  function closeOnboarding() {
202
  document.getElementById('onboard-overlay').style.display = 'none';
203
  }
204
 
205
  // Show onboarding on every page load
206
- document.addEventListener("DOMContentLoaded", () => {
207
- document.getElementById('onboard-overlay').style.display = 'flex';
208
- });
 
 
12
  if (name === 'upload') {
13
  document.getElementById('upload-progress-container').classList.add('hidden');
14
  document.getElementById('dropzone').classList.remove('hidden');
 
15
  document.getElementById('upload-bar').style.width = '0%';
16
  document.getElementById('upload-percentage').innerText = '0%';
17
  document.getElementById('upload-text').innerText = 'Uploading...';
 
30
  }
31
 
32
  if (dropzone) {
33
+ dropzone.addEventListener('dragover', e => {
34
+ e.preventDefault();
35
+ dropzone.classList.add('border-white', 'bg-neutral-950');
36
+ });
37
+ dropzone.addEventListener('dragleave', () => {
38
+ dropzone.classList.remove('border-white', 'bg-neutral-950');
39
+ });
40
  dropzone.addEventListener('drop', e => {
41
  e.preventDefault();
42
  dropzone.classList.remove('border-white', 'bg-neutral-950');
 
45
  }
46
 
47
  let currentXHR = null;
48
+
49
  function uploadFile(file) {
 
50
  if (currentXHR) currentXHR.abort();
51
 
52
  const dropzoneEl = document.getElementById('dropzone');
53
+ const prog = document.getElementById('upload-progress-container');
54
+ const bar = document.getElementById('upload-bar');
55
+ const pct = document.getElementById('upload-percentage');
56
+ const txt = document.getElementById('upload-text');
57
 
58
  if (dropzoneEl) dropzoneEl.classList.add('hidden');
59
+ if (prog) prog.classList.remove('hidden');
60
 
61
  const form = new FormData();
62
  form.append('file', file);
 
97
  .then(cfg => {
98
  runConfig = cfg;
99
  runConfig.conf = 0.12;
100
+ runConfig.iou = 0.60;
101
  txt.innerText = 'Initialization Complete';
102
  fileInput.value = '';
103
  setTimeout(() => showStep('draw'), 800);
104
  })
105
+ .catch(() => {
106
  txt.innerText = 'Metadata Failed';
107
  txt.classList.add('text-red-500');
108
  fileInput.value = '';
109
  });
110
  };
111
+
112
  xhr.send(form);
113
  }
114
 
115
+ // Draw Canvas
116
  const canvas = document.getElementById('drawing-canvas');
117
+ const ctx = canvas ? canvas.getContext('2d') : null;
118
+ let points = [];
119
+ let imgNatW = 0, imgNatH = 0;
120
 
121
  function loadFirstFrame() {
122
+ const img = document.getElementById('frame-img');
123
  const placeholder = document.getElementById('frame-placeholder');
124
+
125
  img.onerror = () => {
126
  console.error('Failed to load first frame');
127
+ if (placeholder) {
128
+ placeholder.innerHTML = '<i class="fa-solid fa-circle-exclamation text-4xl mb-3 opacity-50" style="color:#c89a6c"></i><span class="font-bold text-[10px] uppercase tracking-widest opacity-50 block mt-2">Frame Load Error</span>';
129
+ }
130
  };
131
 
132
  img.src = '/first-frame/' + videoId;
 
134
  imgNatW = img.naturalWidth;
135
  imgNatH = img.naturalHeight;
136
  img.style.display = 'block';
137
+ if (placeholder) placeholder.style.display = 'none';
138
  initCanvas();
139
  };
140
  }
141
 
142
  function initCanvas() {
143
  if (canvas) {
144
+ canvas.width = canvas.offsetWidth;
145
  canvas.height = canvas.offsetHeight;
146
  }
147
  }
 
152
  canvas.addEventListener('mousedown', e => {
153
  if (points.length >= 2) return;
154
  const rect = canvas.getBoundingClientRect();
155
+ const cx = e.clientX - rect.left;
156
+ const cy = e.clientY - rect.top;
157
+ const rx = (cx / canvas.width) * imgNatW;
158
+ const ry = (cy / canvas.height) * imgNatH;
159
  points.push({ cx, cy, rx: Math.round(rx), ry: Math.round(ry) });
160
  drawDot(cx, cy);
161
  if (points.length === 2) drawLine();
 
165
  function drawDot(x, y) {
166
  ctx.beginPath();
167
  ctx.arc(x, y, 5, 0, Math.PI * 2);
168
+ ctx.fillStyle = '#c89a6c';
169
  ctx.fill();
170
  ctx.strokeStyle = '#f0ece6';
171
+ ctx.lineWidth = 2;
172
  ctx.stroke();
173
  }
174
 
 
177
  ctx.moveTo(points[0].cx, points[0].cy);
178
  ctx.lineTo(points[1].cx, points[1].cy);
179
  ctx.strokeStyle = '#c89a6c';
180
+ ctx.lineWidth = 3;
181
  ctx.stroke();
182
  }
183
 
184
  function resetCanvas() {
185
  points = [];
186
+ if (ctx) ctx.clearRect(0, 0, canvas.width, canvas.height);
187
  }
188
 
189
  function startRun() {
 
191
  const line = [[points[0].rx, points[0].ry], [points[1].rx, points[1].ry]];
192
  sessionStorage.setItem('funky_run', JSON.stringify({
193
  video_id: videoId,
194
+ line: line,
195
+ config: runConfig
196
  }));
197
  window.location.href = '/';
198
  }
199
 
200
+ // Onboarding
201
  let _obStep = 0;
202
+
203
  function nextOnboardStep() {
204
  _obStep++;
205
  if (_obStep >= 3) { closeOnboarding(); return; }
206
  document.querySelectorAll('.onboard-step').forEach((s, i) => s.classList.toggle('active', i === _obStep));
207
+ document.querySelectorAll('.onboard-dot').forEach((d, i) => d.classList.toggle('active', i === _obStep));
208
  if (_obStep === 2) document.getElementById('onboard-next').innerText = 'Get Started';
209
  }
210
+
211
  function closeOnboarding() {
212
  document.getElementById('onboard-overlay').style.display = 'none';
213
  }
214
 
215
  // Show onboarding on every page load
216
+ document.addEventListener('DOMContentLoaded', () => {
217
+ const onboard = document.getElementById('onboard-overlay');
218
+ if (onboard) onboard.style.display = 'flex';
219
+ });