style: upgrade frontend to match floodzy.id aesthetics with custom cyber HUD cursor, map radar sweep, progress bar glowing states, and ambient lens light effects
Browse files- static/app.js +64 -0
- static/index.html +4 -0
- static/style.css +140 -0
static/app.js
CHANGED
|
@@ -861,3 +861,67 @@ function animate() {
|
|
| 861 |
}
|
| 862 |
|
| 863 |
animate();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 861 |
}
|
| 862 |
|
| 863 |
animate();
|
| 864 |
+
|
| 865 |
+
// ==========================================
|
| 866 |
+
// CUSTOM CYBER HUD CURSOR
|
| 867 |
+
// ==========================================
|
| 868 |
+
const cursorDot = document.getElementById("cursor-dot");
|
| 869 |
+
const cursorRing = document.getElementById("cursor-ring");
|
| 870 |
+
|
| 871 |
+
let mouseX = -100;
|
| 872 |
+
let mouseY = -100;
|
| 873 |
+
let ringX = -100;
|
| 874 |
+
let ringY = -100;
|
| 875 |
+
|
| 876 |
+
document.addEventListener("mousemove", (e) => {
|
| 877 |
+
mouseX = e.clientX;
|
| 878 |
+
mouseY = e.clientY;
|
| 879 |
+
|
| 880 |
+
if (cursorDot && cursorDot.style.display !== "block") {
|
| 881 |
+
cursorDot.style.display = "block";
|
| 882 |
+
cursorRing.style.display = "block";
|
| 883 |
+
}
|
| 884 |
+
});
|
| 885 |
+
|
| 886 |
+
function animateCursor() {
|
| 887 |
+
const lerpFactor = 0.15;
|
| 888 |
+
ringX += (mouseX - ringX) * lerpFactor;
|
| 889 |
+
ringY += (mouseY - ringY) * lerpFactor;
|
| 890 |
+
|
| 891 |
+
if (cursorDot) {
|
| 892 |
+
cursorDot.style.transform = `translate3d(${mouseX}px, ${mouseY}px, 0) translate3d(-50%, -50%, 0)`;
|
| 893 |
+
}
|
| 894 |
+
if (cursorRing) {
|
| 895 |
+
cursorRing.style.transform = `translate3d(${ringX}px, ${ringY}px, 0) translate3d(-50%, -50%, 0)`;
|
| 896 |
+
}
|
| 897 |
+
requestAnimationFrame(animateCursor);
|
| 898 |
+
}
|
| 899 |
+
animateCursor();
|
| 900 |
+
|
| 901 |
+
// Mouse hover scaling state
|
| 902 |
+
document.addEventListener("mouseover", (e) => {
|
| 903 |
+
if (cursorRing && (
|
| 904 |
+
e.target.tagName === "BUTTON" ||
|
| 905 |
+
e.target.tagName === "A" ||
|
| 906 |
+
e.target.tagName === "SELECT" ||
|
| 907 |
+
e.target.tagName === "INPUT" ||
|
| 908 |
+
e.target.classList.contains("leaflet-interactive") ||
|
| 909 |
+
e.target.closest("button") ||
|
| 910 |
+
e.target.closest("a")
|
| 911 |
+
)) {
|
| 912 |
+
cursorRing.classList.add("hover-state");
|
| 913 |
+
}
|
| 914 |
+
});
|
| 915 |
+
document.addEventListener("mouseout", (e) => {
|
| 916 |
+
if (cursorRing && (
|
| 917 |
+
e.target.tagName === "BUTTON" ||
|
| 918 |
+
e.target.tagName === "A" ||
|
| 919 |
+
e.target.tagName === "SELECT" ||
|
| 920 |
+
e.target.tagName === "INPUT" ||
|
| 921 |
+
e.target.classList.contains("leaflet-interactive") ||
|
| 922 |
+
e.target.closest("button") ||
|
| 923 |
+
e.target.closest("a")
|
| 924 |
+
)) {
|
| 925 |
+
cursorRing.classList.remove("hover-state");
|
| 926 |
+
}
|
| 927 |
+
});
|
static/index.html
CHANGED
|
@@ -413,6 +413,10 @@
|
|
| 413 |
<p>© 2026 Aeterna AI - DKI Jakarta Waste Management Intelligence. Calibrated with DLH & Open-Meteo.</p>
|
| 414 |
</footer>
|
| 415 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 416 |
<!-- Scripts -->
|
| 417 |
<script src="/static/app.js"></script>
|
| 418 |
</body>
|
|
|
|
| 413 |
<p>© 2026 Aeterna AI - DKI Jakarta Waste Management Intelligence. Calibrated with DLH & Open-Meteo.</p>
|
| 414 |
</footer>
|
| 415 |
|
| 416 |
+
<!-- Custom Cyber HUD Cursor -->
|
| 417 |
+
<div id="cursor-dot"></div>
|
| 418 |
+
<div id="cursor-ring"></div>
|
| 419 |
+
|
| 420 |
<!-- Scripts -->
|
| 421 |
<script src="/static/app.js"></script>
|
| 422 |
</body>
|
static/style.css
CHANGED
|
@@ -1163,4 +1163,144 @@ footer {
|
|
| 1163 |
color: var(--text-muted);
|
| 1164 |
}
|
| 1165 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1166 |
|
|
|
|
| 1163 |
color: var(--text-muted);
|
| 1164 |
}
|
| 1165 |
|
| 1166 |
+
/* ==========================================
|
| 1167 |
+
CUSTOM CYBER HUD CURSOR & INTERACTIVITY
|
| 1168 |
+
========================================== */
|
| 1169 |
+
#cursor-dot,
|
| 1170 |
+
#cursor-ring {
|
| 1171 |
+
position: fixed;
|
| 1172 |
+
top: 0;
|
| 1173 |
+
left: 0;
|
| 1174 |
+
pointer-events: none;
|
| 1175 |
+
z-index: 10000;
|
| 1176 |
+
border-radius: 50%;
|
| 1177 |
+
display: none;
|
| 1178 |
+
backface-visibility: hidden;
|
| 1179 |
+
}
|
| 1180 |
+
|
| 1181 |
+
#cursor-dot {
|
| 1182 |
+
width: 6px;
|
| 1183 |
+
height: 6px;
|
| 1184 |
+
background: var(--cyan);
|
| 1185 |
+
box-shadow: 0 0 10px var(--cyan);
|
| 1186 |
+
}
|
| 1187 |
+
|
| 1188 |
+
#cursor-ring {
|
| 1189 |
+
width: 40px;
|
| 1190 |
+
height: 40px;
|
| 1191 |
+
border: 1px solid var(--border-hover);
|
| 1192 |
+
transition: width 0.25s cubic-bezier(0.25, 1, 0.5, 1),
|
| 1193 |
+
height 0.25s cubic-bezier(0.25, 1, 0.5, 1),
|
| 1194 |
+
border-color 0.25s ease,
|
| 1195 |
+
background 0.25s ease;
|
| 1196 |
+
}
|
| 1197 |
+
|
| 1198 |
+
/* Hover state on buttons/interactive elements */
|
| 1199 |
+
#cursor-ring.hover-state {
|
| 1200 |
+
width: 55px;
|
| 1201 |
+
height: 55px;
|
| 1202 |
+
border-color: var(--cyan);
|
| 1203 |
+
background: rgba(0, 240, 255, 0.04);
|
| 1204 |
+
box-shadow: 0 0 15px rgba(0, 240, 255, 0.15);
|
| 1205 |
+
}
|
| 1206 |
+
|
| 1207 |
+
@media (pointer: coarse) {
|
| 1208 |
+
#cursor-dot,
|
| 1209 |
+
#cursor-ring {
|
| 1210 |
+
display: none !important;
|
| 1211 |
+
}
|
| 1212 |
+
* {
|
| 1213 |
+
cursor: auto !important;
|
| 1214 |
+
}
|
| 1215 |
+
}
|
| 1216 |
+
|
| 1217 |
+
/* Hide default cursor on desktops for the custom cursor feel */
|
| 1218 |
+
@media (pointer: fine) {
|
| 1219 |
+
body, a, button, select, input, [role="button"], .leaflet-interactive {
|
| 1220 |
+
cursor: none !important;
|
| 1221 |
+
}
|
| 1222 |
+
}
|
| 1223 |
+
|
| 1224 |
+
/* ==========================================
|
| 1225 |
+
RADAR SWEEP EFFECT (ON MAP OVERLAY)
|
| 1226 |
+
========================================== */
|
| 1227 |
+
.map-container {
|
| 1228 |
+
position: relative;
|
| 1229 |
+
}
|
| 1230 |
+
|
| 1231 |
+
.map-container::after {
|
| 1232 |
+
content: '';
|
| 1233 |
+
position: absolute;
|
| 1234 |
+
inset: 0;
|
| 1235 |
+
pointer-events: none;
|
| 1236 |
+
z-index: 1000;
|
| 1237 |
+
background: conic-gradient(from 0deg at 50% 50%, rgba(0, 240, 255, 0.08) 0deg, transparent 90deg, transparent 360deg);
|
| 1238 |
+
animation: radar-sweep 8s linear infinite;
|
| 1239 |
+
opacity: 0.7;
|
| 1240 |
+
border-radius: 8px;
|
| 1241 |
+
mix-blend-mode: screen;
|
| 1242 |
+
}
|
| 1243 |
+
|
| 1244 |
+
@keyframes radar-sweep {
|
| 1245 |
+
from {
|
| 1246 |
+
transform: rotate(0deg);
|
| 1247 |
+
}
|
| 1248 |
+
to {
|
| 1249 |
+
transform: rotate(360deg);
|
| 1250 |
+
}
|
| 1251 |
+
}
|
| 1252 |
+
|
| 1253 |
+
/* ==========================================
|
| 1254 |
+
AMBIENT GLOWS & GLASSMORPHISM UPGRADES
|
| 1255 |
+
========================================== */
|
| 1256 |
+
body::before {
|
| 1257 |
+
content: '';
|
| 1258 |
+
position: fixed;
|
| 1259 |
+
top: -10%;
|
| 1260 |
+
left: -10%;
|
| 1261 |
+
width: 50%;
|
| 1262 |
+
height: 50%;
|
| 1263 |
+
background: radial-gradient(circle, rgba(0, 240, 255, 0.05) 0%, transparent 70%);
|
| 1264 |
+
z-index: 0;
|
| 1265 |
+
pointer-events: none;
|
| 1266 |
+
}
|
| 1267 |
+
|
| 1268 |
+
body::after {
|
| 1269 |
+
content: '';
|
| 1270 |
+
position: fixed;
|
| 1271 |
+
bottom: -10%;
|
| 1272 |
+
right: -10%;
|
| 1273 |
+
width: 60%;
|
| 1274 |
+
height: 60%;
|
| 1275 |
+
background: radial-gradient(circle, rgba(0, 102, 255, 0.04) 0%, transparent 70%);
|
| 1276 |
+
z-index: 0;
|
| 1277 |
+
pointer-events: none;
|
| 1278 |
+
}
|
| 1279 |
+
|
| 1280 |
+
/* Neon glow for progress bars */
|
| 1281 |
+
.progress-bar-fill.organic {
|
| 1282 |
+
box-shadow: 0 0 8px var(--green-glow);
|
| 1283 |
+
}
|
| 1284 |
+
.progress-bar-fill.plastic {
|
| 1285 |
+
box-shadow: 0 0 8px var(--cyan-glow);
|
| 1286 |
+
}
|
| 1287 |
+
.progress-bar-fill.paper {
|
| 1288 |
+
box-shadow: 0 0 8px var(--yellow-glow);
|
| 1289 |
+
}
|
| 1290 |
+
.progress-bar-fill.glass {
|
| 1291 |
+
box-shadow: 0 0 8px rgba(0, 240, 255, 0.25);
|
| 1292 |
+
}
|
| 1293 |
+
.progress-bar-fill.textile {
|
| 1294 |
+
box-shadow: 0 0 8px rgba(255, 0, 85, 0.25);
|
| 1295 |
+
}
|
| 1296 |
+
.progress-bar-fill.metal {
|
| 1297 |
+
box-shadow: 0 0 8px rgba(255, 255, 255, 0.25);
|
| 1298 |
+
}
|
| 1299 |
+
|
| 1300 |
+
/* Logo Reflective Polish */
|
| 1301 |
+
.logo-text {
|
| 1302 |
+
position: relative;
|
| 1303 |
+
-webkit-box-reflect: below -4px linear-gradient(transparent, rgba(255, 255, 255, 0.08));
|
| 1304 |
+
}
|
| 1305 |
+
|
| 1306 |
|