Update signup success message and clean up workspace
|
After Width: | Height: | Size: 448 KiB |
|
After Width: | Height: | Size: 450 KiB |
BIN
public/PragatiVeer_Logo/PNG_Logos/Square_dark_background.png
Normal file
|
After Width: | Height: | Size: 1.7 MiB |
BIN
public/PragatiVeer_Logo/PNG_Logos/Square_light_background.png
Normal file
|
After Width: | Height: | Size: 1.8 MiB |
|
After Width: | Height: | Size: 494 KiB |
|
After Width: | Height: | Size: 460 KiB |
|
After Width: | Height: | Size: 1.4 MiB |
|
After Width: | Height: | Size: 2.4 MiB |
BIN
public/course_business.png
Normal file
|
After Width: | Height: | Size: 440 KiB |
BIN
public/course_design.png
Normal file
|
After Width: | Height: | Size: 581 KiB |
BIN
public/course_tech.png
Normal file
|
After Width: | Height: | Size: 524 KiB |
BIN
public/dpps/dps-bio-ch4-20260707.pdf
Normal file
BIN
public/dpps/dps-che-ch4-20260707.pdf
Normal file
BIN
public/dpps/dps-mth-ch4-20260707.pdf
Normal file
BIN
public/dpps/dps-phy-ch4-20260707.pdf
Normal file
1
public/file.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg fill="none" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="M14.5 13.5V5.41a1 1 0 0 0-.3-.7L9.8.29A1 1 0 0 0 9.08 0H1.5v13.5A2.5 2.5 0 0 0 4 16h8a2.5 2.5 0 0 0 2.5-2.5m-1.5 0v-7H8v-5H3v12a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1M9.5 5V2.12L12.38 5zM5.13 5h-.62v1.25h2.12V5zm-.62 3h7.12v1.25H4.5zm.62 3h-.62v1.25h7.12V11z" clip-rule="evenodd" fill="#666" fill-rule="evenodd"/></svg>
|
||||
|
After Width: | Height: | Size: 391 B |
1
public/globe.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><g clip-path="url(#a)"><path fill-rule="evenodd" clip-rule="evenodd" d="M10.27 14.1a6.5 6.5 0 0 0 3.67-3.45q-1.24.21-2.7.34-.31 1.83-.97 3.1M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16m.48-1.52a7 7 0 0 1-.96 0H7.5a4 4 0 0 1-.84-1.32q-.38-.89-.63-2.08a40 40 0 0 0 3.92 0q-.25 1.2-.63 2.08a4 4 0 0 1-.84 1.31zm2.94-4.76q1.66-.15 2.95-.43a7 7 0 0 0 0-2.58q-1.3-.27-2.95-.43a18 18 0 0 1 0 3.44m-1.27-3.54a17 17 0 0 1 0 3.64 39 39 0 0 1-4.3 0 17 17 0 0 1 0-3.64 39 39 0 0 1 4.3 0m1.1-1.17q1.45.13 2.69.34a6.5 6.5 0 0 0-3.67-3.44q.65 1.26.98 3.1M8.48 1.5l.01.02q.41.37.84 1.31.38.89.63 2.08a40 40 0 0 0-3.92 0q.25-1.2.63-2.08a4 4 0 0 1 .85-1.32 7 7 0 0 1 .96 0m-2.75.4a6.5 6.5 0 0 0-3.67 3.44 29 29 0 0 1 2.7-.34q.31-1.83.97-3.1M4.58 6.28q-1.66.16-2.95.43a7 7 0 0 0 0 2.58q1.3.27 2.95.43a18 18 0 0 1 0-3.44m.17 4.71q-1.45-.12-2.69-.34a6.5 6.5 0 0 0 3.67 3.44q-.65-1.27-.98-3.1" fill="#666"/></g><defs><clipPath id="a"><path fill="#fff" d="M0 0h16v16H0z"/></clipPath></defs></svg>
|
||||
|
After Width: | Height: | Size: 1.0 KiB |
1
public/next.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 394 80"><path fill="#000" d="M262 0h68.5v12.7h-27.2v66.6h-13.6V12.7H262V0ZM149 0v12.7H94v20.4h44.3v12.6H94v21h55v12.6H80.5V0h68.7zm34.3 0h-17.8l63.8 79.4h17.9l-32-39.7 32-39.6h-17.9l-23 28.6-23-28.6zm18.3 56.7-9-11-27.1 33.7h17.8l18.3-22.7z"/><path fill="#000" d="M81 79.3 17 0H0v79.3h13.6V17l50.2 62.3H81Zm252.6-.4c-1 0-1.8-.4-2.5-1s-1.1-1.6-1.1-2.6.3-1.8 1-2.5 1.6-1 2.6-1 1.8.3 2.5 1a3.4 3.4 0 0 1 .6 4.3 3.7 3.7 0 0 1-3 1.8zm23.2-33.5h6v23.3c0 2.1-.4 4-1.3 5.5a9.1 9.1 0 0 1-3.8 3.5c-1.6.8-3.5 1.3-5.7 1.3-2 0-3.7-.4-5.3-1s-2.8-1.8-3.7-3.2c-.9-1.3-1.4-3-1.4-5h6c.1.8.3 1.6.7 2.2s1 1.2 1.6 1.5c.7.4 1.5.5 2.4.5 1 0 1.8-.2 2.4-.6a4 4 0 0 0 1.6-1.8c.3-.8.5-1.8.5-3V45.5zm30.9 9.1a4.4 4.4 0 0 0-2-3.3 7.5 7.5 0 0 0-4.3-1.1c-1.3 0-2.4.2-3.3.5-.9.4-1.6 1-2 1.6a3.5 3.5 0 0 0-.3 4c.3.5.7.9 1.3 1.2l1.8 1 2 .5 3.2.8c1.3.3 2.5.7 3.7 1.2a13 13 0 0 1 3.2 1.8 8.1 8.1 0 0 1 3 6.5c0 2-.5 3.7-1.5 5.1a10 10 0 0 1-4.4 3.5c-1.8.8-4.1 1.2-6.8 1.2-2.6 0-4.9-.4-6.8-1.2-2-.8-3.4-2-4.5-3.5a10 10 0 0 1-1.7-5.6h6a5 5 0 0 0 3.5 4.6c1 .4 2.2.6 3.4.6 1.3 0 2.5-.2 3.5-.6 1-.4 1.8-1 2.4-1.7a4 4 0 0 0 .8-2.4c0-.9-.2-1.6-.7-2.2a11 11 0 0 0-2.1-1.4l-3.2-1-3.8-1c-2.8-.7-5-1.7-6.6-3.2a7.2 7.2 0 0 1-2.4-5.7 8 8 0 0 1 1.7-5 10 10 0 0 1 4.3-3.5c2-.8 4-1.2 6.4-1.2 2.3 0 4.4.4 6.2 1.2 1.8.8 3.2 2 4.3 3.4 1 1.4 1.5 3 1.5 5h-5.8z"/></svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
449
public/streak-animation.html
Normal file
@@ -0,0 +1,449 @@
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>PRAGATIVEER · Reveal</title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;600;700&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
:root{
|
||||
--navy-900:#000000; --navy-800:#000000; --navy-700:#000000;
|
||||
--gold-200:#fdeeb8; --gold-300:#f6dd93; --gold-400:#e8c463; --gold-500:#d4af37;
|
||||
--gold-600:#b1892a; --gold-700:#7d5f18;
|
||||
--ink:#e9eefb; --badge:240px; --grow:1.18; --halo-w:170%;
|
||||
--font:"Space Grotesk", ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, sans-serif;
|
||||
}
|
||||
*{box-sizing:border-box}
|
||||
html,body{height:100%}
|
||||
body{
|
||||
margin:0; font-family:var(--font); color:var(--ink);
|
||||
background:radial-gradient(120% 90% at 50% -10%, #000000 0%, var(--navy-800) 42%, var(--navy-900) 100%);
|
||||
display:flex; align-items:center; justify-content:center; overflow:hidden;
|
||||
-webkit-font-smoothing:antialiased; transition:background .6s ease;
|
||||
}
|
||||
/* sad sky */
|
||||
body.sad{background:radial-gradient(120% 90% at 50% -10%, #000000 0%, #000000 46%, #000000 100%)}
|
||||
body::after{
|
||||
content:""; position:fixed; inset:0; pointer-events:none; z-index:0;
|
||||
background:radial-gradient(70% 60% at 50% 44%, transparent 55%, rgba(0,0,0,.45) 100%);
|
||||
mix-blend-mode:multiply;
|
||||
}
|
||||
|
||||
#fw{position:fixed; inset:0; z-index:5; pointer-events:none}
|
||||
|
||||
/* euphoric gold flash */
|
||||
.flash{position:fixed; inset:0; z-index:6; pointer-events:none; opacity:0;
|
||||
background:radial-gradient(circle at 50% 46%, rgba(255,240,190,.6), rgba(212,175,55,.15) 45%, transparent 70%)}
|
||||
.stage.play.tier3 .flash{animation:flash 760ms ease-out 2600ms}
|
||||
|
||||
.stage{
|
||||
position:relative; z-index:10; width:min(92vw,560px); height:100dvh;
|
||||
display:flex; flex-direction:column; align-items:center; justify-content:center;
|
||||
gap:26px; padding:24px; text-align:center;
|
||||
}
|
||||
|
||||
.scene{
|
||||
position:relative; width:var(--badge); height:var(--badge);
|
||||
perspective:1300px; perspective-origin:50% 46%;
|
||||
display:flex; align-items:center; justify-content:center;
|
||||
}
|
||||
.stage.play.tier3 .scene{animation:shake 520ms ease-out 2620ms}
|
||||
|
||||
.halo{
|
||||
position:absolute; top:50%; left:50%; width:var(--halo-w); aspect-ratio:1;
|
||||
transform:translate(-50%,-50%) scale(.3); opacity:0; border-radius:50%; filter:blur(4px); z-index:0;
|
||||
background:radial-gradient(circle,
|
||||
rgba(246,221,147,.55) 0%, rgba(212,175,55,.35) 34%, rgba(212,175,55,.08) 58%, transparent 72%);
|
||||
}
|
||||
.stage.play.happy .halo{animation:bloom 850ms cubic-bezier(.2,.8,.3,1) 1850ms forwards, pulse 2.8s ease-in-out 2700ms infinite}
|
||||
.stage.sad .halo{
|
||||
background:radial-gradient(circle, rgba(100,100,100,.30) 0%, rgba(80,80,80,.14) 42%, transparent 70%);
|
||||
}
|
||||
.stage.play.sad .halo{animation:bloomcold 1000ms ease-out 1900ms forwards}
|
||||
|
||||
.scaler{position:relative; width:100%; height:100%; z-index:1; transform:scale(1)}
|
||||
.stage.play.happy .scaler{animation:grow 680ms cubic-bezier(.34,1.56,.5,1) 2050ms forwards, litglow 700ms ease-out 1900ms forwards}
|
||||
.stage.play.sad .scaler{animation:droop 950ms cubic-bezier(.3,.7,.4,1) 2050ms forwards, dimglow 800ms ease-out 1900ms forwards}
|
||||
|
||||
.spinner{position:absolute; inset:0; will-change:transform; transform:rotateY(0deg) scale(0)}
|
||||
.stage.play .spinner{animation:spin 1800ms cubic-bezier(.14,.62,.2,1) 150ms forwards}
|
||||
|
||||
.badge{
|
||||
position:absolute; inset:0; border-radius:50%;
|
||||
background: url('/PragatiVeer_Logo/SVG_Logos/Square_dark_background.svg') center/cover no-repeat !important;
|
||||
}
|
||||
.stage.sad .badge{
|
||||
position:absolute; inset:0; border-radius:50%;
|
||||
background: url('/PragatiVeer_Logo/SVG_Logos/Square_dark_background.svg') center/cover no-repeat !important;
|
||||
}
|
||||
|
||||
.count{
|
||||
position:relative; z-index:1; display:flex; flex-direction:column; align-items:center; gap:6px;
|
||||
opacity:0; transform:translateY(14px) scale(.9);
|
||||
}
|
||||
.stage.play .count{animation:reveal 620ms cubic-bezier(.34,1.4,.5,1) 2650ms forwards}
|
||||
.number{
|
||||
font-size:clamp(56px,17vw,88px); font-weight:700; line-height:.92; letter-spacing:-.02em;
|
||||
background:linear-gradient(180deg,var(--gold-200),var(--gold-500) 55%,var(--gold-600));
|
||||
-webkit-background-clip:text; background-clip:text; color:transparent;
|
||||
font-variant-numeric:tabular-nums; filter:drop-shadow(0 4px 18px rgba(212,175,55,.35));
|
||||
}
|
||||
.stage.sad .number{
|
||||
background:linear-gradient(180deg,#c7d0e0,#8b97ad 58%,#68738a);
|
||||
-webkit-background-clip:text; background-clip:text; filter:drop-shadow(0 3px 12px rgba(80,105,140,.3));
|
||||
}
|
||||
.caption{
|
||||
font-size:12px; font-weight:600; letter-spacing:.34em; text-transform:uppercase;
|
||||
color:var(--gold-400); text-indent:.34em; min-height:14px; transition:color .5s ease;
|
||||
}
|
||||
.stage.sad .caption{color:#95a2ba}
|
||||
|
||||
.panel{
|
||||
position:absolute; bottom:22px; left:50%; transform:translateX(-50%);
|
||||
display:flex; gap:8px; align-items:center; flex-wrap:wrap; justify-content:center;
|
||||
background:rgba(9,20,40,.55); border:1px solid rgba(232,196,99,.22);
|
||||
padding:8px 8px 8px 14px; border-radius:14px; backdrop-filter:blur(8px); box-shadow:0 10px 30px rgba(0,0,0,.4);
|
||||
}
|
||||
.panel label{font-size:11px; letter-spacing:.14em; text-transform:uppercase; color:rgba(233,238,251,.55)}
|
||||
.panel input{
|
||||
width:110px; background:rgba(255,255,255,.06); border:1px solid rgba(232,196,99,.25);
|
||||
color:var(--ink); font-family:var(--font); font-size:14px; font-weight:500; padding:8px 10px; border-radius:9px; outline:none;
|
||||
}
|
||||
.panel input.cap{width:104px; text-transform:uppercase; letter-spacing:.1em; font-size:12px}
|
||||
.panel input:focus{border-color:var(--gold-400); box-shadow:0 0 0 3px rgba(212,175,55,.18)}
|
||||
.replay{
|
||||
border:none; cursor:pointer; font-family:var(--font); font-weight:600; font-size:13px; letter-spacing:.06em;
|
||||
color:#20130a; padding:9px 16px; border-radius:9px;
|
||||
background:linear-gradient(180deg,var(--gold-300),var(--gold-500)); box-shadow:0 4px 14px rgba(212,175,55,.35);
|
||||
transition:transform .12s ease, box-shadow .12s ease;
|
||||
}
|
||||
.replay:hover{transform:translateY(-1px); box-shadow:0 7px 18px rgba(212,175,55,.45)}
|
||||
.replay:active{transform:translateY(0)}
|
||||
.replay:focus-visible, .panel input:focus-visible{outline:2px solid var(--gold-300); outline-offset:2px}
|
||||
.hint{font-size:10.5px; color:rgba(233,238,251,.4); letter-spacing:.02em; margin-top:2px}
|
||||
|
||||
@media (max-width:460px){ :root{--badge:180px} .panel input{width:94px} .panel input.cap{width:88px} }
|
||||
|
||||
@keyframes spin{ 0%{transform:rotateY(0deg) scale(0)} 100%{transform:rotateY(1440deg) scale(1)} }
|
||||
@keyframes bloom{
|
||||
0%{opacity:0; transform:translate(-50%,-50%) scale(.3)}
|
||||
60%{opacity:1; transform:translate(-50%,-50%) scale(1.06)}
|
||||
100%{opacity:.9; transform:translate(-50%,-50%) scale(1)}
|
||||
}
|
||||
@keyframes bloomcold{
|
||||
0%{opacity:0; transform:translate(-50%,-50%) scale(.3)}
|
||||
100%{opacity:.5; transform:translate(-50%,-50%) scale(.82)}
|
||||
}
|
||||
@keyframes pulse{ 0%,100%{opacity:.75; transform:translate(-50%,-50%) scale(1)} 50%{opacity:1; transform:translate(-50%,-50%) scale(1.05)} }
|
||||
@keyframes grow{ 0%{transform:scale(1)} 70%{transform:scale(calc(var(--grow) + .06))} 100%{transform:scale(var(--grow))} }
|
||||
@keyframes droop{ 0%{transform:scale(1) translateY(0)} 100%{transform:scale(.93) translateY(9px)} }
|
||||
@keyframes litglow{ 0%{filter:drop-shadow(0 0 0 rgba(212,175,55,0))} 100%{filter:drop-shadow(0 0 26px rgba(233,196,99,.6))} }
|
||||
@keyframes dimglow{ 0%{filter:drop-shadow(0 0 0 rgba(120,150,190,0))} 100%{filter:drop-shadow(0 6px 16px rgba(20,30,45,.5))} }
|
||||
@keyframes reveal{ 0%{opacity:0; transform:translateY(14px) scale(.9)} 100%{opacity:1; transform:translateY(0) scale(1)} }
|
||||
@keyframes flash{ 0%{opacity:0} 18%{opacity:.85} 100%{opacity:0} }
|
||||
@keyframes shake{
|
||||
0%,100%{transform:translate(0,0)} 20%{transform:translate(-4px,2px)} 40%{transform:translate(4px,-2px)}
|
||||
60%{transform:translate(-3px,-1px)} 80%{transform:translate(3px,1px)}
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion:reduce){
|
||||
.stage.play .spinner{animation:none; transform:rotateY(0) scale(1)}
|
||||
.stage.play.happy .scaler{animation:none; transform:scale(var(--grow)); filter:drop-shadow(0 0 26px rgba(233,196,99,.6))}
|
||||
.stage.play.sad .scaler{animation:none; transform:scale(.93) translateY(9px)}
|
||||
.stage.play.happy .halo{animation:none; opacity:.9; transform:translate(-50%,-50%) scale(1)}
|
||||
.stage.play.sad .halo{animation:none; opacity:.5; transform:translate(-50%,-50%) scale(.82)}
|
||||
.stage.play .count{animation:none; opacity:1; transform:none}
|
||||
.stage.play.tier3 .scene,.stage.play.tier3 .flash{animation:none}
|
||||
}
|
||||
|
||||
body, html {
|
||||
background: transparent !important;
|
||||
background-image: none !important;
|
||||
}
|
||||
body.sad {
|
||||
background: transparent !important;
|
||||
background-image: none !important;
|
||||
}
|
||||
body::after {
|
||||
display: none !important;
|
||||
}
|
||||
.stage {
|
||||
height: 100vh !important;
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
padding: 0 !important;
|
||||
gap: 0 !important;
|
||||
justify-content: center !important;
|
||||
}
|
||||
.count, .panel, .hint {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<canvas id="fw"></canvas>
|
||||
<div class="flash"></div>
|
||||
|
||||
<div class="stage" id="stage">
|
||||
<div class="scene">
|
||||
<div class="halo"></div>
|
||||
<div class="scaler"><div class="spinner"><div class="badge"></div></div></div>
|
||||
</div>
|
||||
|
||||
<div class="count">
|
||||
<div class="number" id="number">0</div>
|
||||
<div class="caption" id="caption">GROWTH SCORE</div>
|
||||
</div>
|
||||
|
||||
<div class="panel">
|
||||
<label for="num">Number</label>
|
||||
<input id="num" type="text" inputmode="numeric" value="2,026" aria-label="Target number">
|
||||
<input id="cap" class="cap" type="text" value="GROWTH SCORE" aria-label="Caption" maxlength="16">
|
||||
<button class="replay" id="replay">Replay</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hint" style="position:absolute;bottom:6px;left:50%;transform:translateX(-50%);z-index:11">
|
||||
under 5 = sad · higher = bigger celebration
|
||||
</div>
|
||||
|
||||
<script>
|
||||
(function(){
|
||||
let isLight = false;
|
||||
try {
|
||||
isLight = !window.parent.document.documentElement.classList.contains('dark');
|
||||
} catch (e) {
|
||||
const p = new URLSearchParams(window.location.search);
|
||||
isLight = p.get('theme') === 'light';
|
||||
}
|
||||
window.isLightTheme = isLight;
|
||||
})();
|
||||
|
||||
const stage=document.getElementById('stage');
|
||||
const body=document.body;
|
||||
const numEl=document.getElementById('number');
|
||||
const capEl=document.getElementById('caption');
|
||||
const numInput=document.getElementById('num');
|
||||
const capInput=document.getElementById('cap');
|
||||
const replay=document.getElementById('replay');
|
||||
const reduce=window.matchMedia('(prefers-reduced-motion:reduce)');
|
||||
|
||||
/* ---------- particle canvas (fireworks + rain + confetti) ---------- */
|
||||
const cv=document.getElementById('fw'), ctx=cv.getContext('2d');
|
||||
let W,H,DPR;
|
||||
function resize(){
|
||||
DPR=Math.min(2,window.devicePixelRatio||1);
|
||||
W=cv.width=Math.floor(innerWidth*DPR); H=cv.height=Math.floor(innerHeight*DPR);
|
||||
cv.style.width=innerWidth+'px'; cv.style.height=innerHeight+'px';
|
||||
}
|
||||
resize(); addEventListener('resize',resize);
|
||||
|
||||
const SPARK=window.isLightTheme?['#0891b2','#2563eb','#db2777','#ea580c','#7c3aed','#059669']:['#f6dd93','#e8c463','#d4af37','#fff4cf','#ffffff','#8fb4ff'];
|
||||
const CONF=window.isLightTheme?['#0891b2','#2563eb','#db2777','#ea580c','#7c3aed','#059669','#d97706']:['#f6dd93','#e8c463','#d4af37','#ffffff','#ffd34d'];
|
||||
let parts=[], running=false, mode='fireworks', rafFW=null, fwTimers=[], fadeCol=(window.isLightTheme ? 'rgba(255,255,255,0.22)' : 'rgba(0,0,0,0.22)');
|
||||
|
||||
function burst(xr,yr,count){
|
||||
const x=xr*W, y=yr*H, n=count|0;
|
||||
for(let i=0;i<n;i++){
|
||||
const a=Math.PI*2*(i/n)+Math.random()*0.25, sp=(2+Math.random()*4.4)*DPR;
|
||||
parts.push({t:'spark', x,y, vx:Math.cos(a)*sp, vy:Math.sin(a)*sp-1.1*DPR,
|
||||
life:1, decay:0.010+Math.random()*0.013, col:SPARK[(Math.random()*SPARK.length)|0], size:(1.3+Math.random()*1.9)*DPR});
|
||||
}
|
||||
}
|
||||
function confetti(m){
|
||||
for(let i=0;i<m;i++){
|
||||
parts.push({t:'conf', x:(0.3+Math.random()*0.4)*W, y:-20*DPR,
|
||||
vx:(-1.2+Math.random()*2.4)*DPR, vy:(1.5+Math.random()*2.5)*DPR,
|
||||
rot:Math.random()*7, vr:(-0.2+Math.random()*0.4), life:1,
|
||||
w:(4+Math.random()*4)*DPR, h:(7+Math.random()*6)*DPR, col:CONF[(Math.random()*CONF.length)|0]});
|
||||
}
|
||||
}
|
||||
// s = sadness 0..1 (1 = most sad). One persistent face per side.
|
||||
function drawSadFace(p){
|
||||
const r=p.r, s=p.s, alpha=Math.min(1,p.fi);
|
||||
const yb=Math.sin(p.phase)*3*DPR + s*3*DPR; // gentle bob + slight downward droop
|
||||
ctx.save(); ctx.translate(p.x, p.y+yb); ctx.globalAlpha=alpha;
|
||||
const line=Math.max(1.6,r*0.075), stroke=(window.isLightTheme ? 'rgba(40,60,90,0.92)' : 'rgba(182,200,228,0.92)');
|
||||
|
||||
// face
|
||||
ctx.beginPath(); ctx.arc(0,0,r,0,7);
|
||||
ctx.fillStyle=(window.isLightTheme ? 'rgba(40,60,90,0.15)' : 'rgba(150,175,210,0.13)'); ctx.fill();
|
||||
ctx.lineWidth=line; ctx.strokeStyle=stroke; ctx.stroke();
|
||||
|
||||
const ex=r*0.42, ey=-r*0.12, er=r*0.10;
|
||||
// worried brows: inner ends raised, steeper when sadder
|
||||
const bl=r*0.30, tilt=(0.15+s*0.55);
|
||||
ctx.lineWidth=Math.max(1.6,r*0.08); ctx.strokeStyle=stroke; ctx.lineCap='round';
|
||||
ctx.beginPath(); ctx.moveTo(-ex-bl*0.5, ey-r*0.30 + bl*tilt); ctx.lineTo(-ex+bl*0.5, ey-r*0.30 - bl*tilt*0.6); ctx.stroke();
|
||||
ctx.beginPath(); ctx.moveTo( ex-bl*0.5, ey-r*0.30 - bl*tilt*0.6); ctx.lineTo( ex+bl*0.5, ey-r*0.30 + bl*tilt); ctx.stroke();
|
||||
|
||||
// eyes (droopier when sadder: a lid line cuts the top)
|
||||
ctx.fillStyle=(window.isLightTheme ? 'rgba(40,60,90,0.95)' : 'rgba(205,218,238,0.95)');
|
||||
ctx.beginPath(); ctx.arc(-ex,ey,er,0,7); ctx.fill();
|
||||
ctx.beginPath(); ctx.arc( ex,ey,er,0,7); ctx.fill();
|
||||
|
||||
// mouth: frown depth scales with sadness (quadratic, peak above corners)
|
||||
const mw=r*0.42, my=r*0.5, dip=r*(0.10 + s*0.55);
|
||||
ctx.beginPath(); ctx.moveTo(-mw,my); ctx.quadraticCurveTo(0, my-dip, mw, my);
|
||||
ctx.lineWidth=line; ctx.strokeStyle=stroke; ctx.stroke();
|
||||
|
||||
// tears: none at low sadness, one, then two — with a looping drip
|
||||
const tears = s>0.66 ? 2 : s>0.3 ? 1 : 0;
|
||||
if(tears){
|
||||
const drop=(p.tp % 1);
|
||||
ctx.fillStyle=(window.isLightTheme ? 'rgba(30,144,255,0.92)' : 'rgba(150,205,244,0.92)');
|
||||
const cheeks = tears===2 ? [-ex, ex] : [-ex];
|
||||
for(const cx of cheeks){
|
||||
const ty=ey+er + drop*r*0.9, tr=r*0.085*(1-drop*0.35);
|
||||
ctx.globalAlpha=alpha*(1-drop*0.7);
|
||||
ctx.beginPath(); ctx.arc(cx, ty, tr, 0, 7); ctx.fill();
|
||||
}
|
||||
ctx.globalAlpha=alpha;
|
||||
}
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
function tick(){
|
||||
if(mode==='faces'){ ctx.clearRect(0,0,W,H); }
|
||||
else { ctx.globalCompositeOperation='source-over'; ctx.fillStyle=fadeCol; ctx.fillRect(0,0,W,H); }
|
||||
for(const p of parts){
|
||||
if(p.t==='spark'){
|
||||
p.vx*=0.986; p.vy=p.vy*0.986+0.05*DPR; p.x+=p.vx; p.y+=p.vy; p.life-=p.decay;
|
||||
if(p.life<=0) continue;
|
||||
ctx.globalCompositeOperation='lighter'; ctx.globalAlpha=Math.max(0,p.life); ctx.fillStyle=p.col;
|
||||
ctx.beginPath(); ctx.arc(p.x,p.y,p.size*p.life+0.4,0,7); ctx.fill();
|
||||
} else if(p.t==='sadface'){
|
||||
p.fi+=0.03; p.phase+=0.03; p.tp+=0.010; // persists until replay
|
||||
drawSadFace(p);
|
||||
} else { // conf
|
||||
p.vy+=0.06*DPR; p.x+=p.vx; p.y+=p.vy; p.rot+=p.vr; p.life-=0.006;
|
||||
if(p.y>H+20||p.life<=0){p.life=0; continue;}
|
||||
ctx.globalCompositeOperation='source-over'; ctx.globalAlpha=Math.max(0,Math.min(1,p.life));
|
||||
ctx.save(); ctx.translate(p.x,p.y); ctx.rotate(p.rot); ctx.fillStyle=p.col;
|
||||
ctx.fillRect(-p.w/2,-p.h/2,p.w,p.h); ctx.restore();
|
||||
}
|
||||
}
|
||||
parts=parts.filter(p=>p.life>0);
|
||||
ctx.globalAlpha=1; ctx.globalCompositeOperation='source-over';
|
||||
if(running||parts.length){ rafFW=requestAnimationFrame(tick); }
|
||||
else { ctx.clearRect(0,0,W,H); rafFW=null; }
|
||||
}
|
||||
function stopFw(){ fwTimers.forEach(clearTimeout); fwTimers=[]; running=false; parts=[]; if(W&&H) ctx.clearRect(0,0,W,H); }
|
||||
|
||||
function celebrate(t){ // t: 0..1 intensity
|
||||
stopFw(); parts=[]; mode='fireworks'; fadeCol=(window.isLightTheme ? 'rgba(255,255,255,0.22)' : 'rgba(0,0,0,0.22)'); running=true;
|
||||
if(!rafFW) rafFW=requestAnimationFrame(tick);
|
||||
const rounds=Math.round(5+t*10); // 5..15
|
||||
const gap=Math.round(345-t*155); // 345..190 ms
|
||||
const base=Math.round(34+t*46); // particles per burst
|
||||
for(let k=0;k<rounds;k++){
|
||||
const d=k*gap;
|
||||
fwTimers.push(setTimeout(()=>burst(0.10+Math.random()*0.07, 0.30+Math.random()*0.24, base), d)); // left
|
||||
fwTimers.push(setTimeout(()=>burst(0.83+Math.random()*0.07, 0.30+Math.random()*0.24, base), d)); // right
|
||||
if(t>0.4) fwTimers.push(setTimeout(()=>burst(0.44+Math.random()*0.12, 0.20+Math.random()*0.14, base+8), d+90)); // center-top
|
||||
if(t>0.75) confetti(6);
|
||||
}
|
||||
fwTimers.push(setTimeout(()=>{ running=false; }, rounds*gap+400));
|
||||
}
|
||||
function sadFaces(s){ // s: 0..1 sadness (1 = most sad)
|
||||
stopFw(); parts=[]; mode='faces'; running=true;
|
||||
if(!rafFW) rafFW=requestAnimationFrame(tick);
|
||||
const r=Math.min(W,H)*0.085 + s*Math.min(W,H)*0.02; // slightly bigger when sadder
|
||||
const y=H*0.42;
|
||||
parts.push({t:'sadface', x:W*0.17, y, r, s, phase:0, tp:Math.random(), fi:0, life:1});
|
||||
parts.push({t:'sadface', x:W*0.83, y, r, s, phase:1.6, tp:Math.random()+0.4, fi:0, life:1});
|
||||
// keep running so the two faces persist (with idle bob + tears) until replay
|
||||
}
|
||||
|
||||
/* ---------- number ---------- */
|
||||
let countRAF=null, countTimer=null, moodTimer=null;
|
||||
|
||||
const parseTarget=()=>{
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
const s = params.get('streak');
|
||||
const v=parseFloat(s);
|
||||
return isFinite(v)?v:0;
|
||||
};
|
||||
|
||||
function countUp(target){
|
||||
const dur=1300, start=performance.now(), ease=t=>1-Math.pow(1-t,3);
|
||||
const decimals=(String(target).split('.')[1]||'').length;
|
||||
(function frame(now){
|
||||
const t=Math.min(1,(now-start)/dur), val=target*ease(t);
|
||||
numEl.textContent=val.toLocaleString(undefined,{minimumFractionDigits:decimals,maximumFractionDigits:decimals});
|
||||
if(t<1) countRAF=requestAnimationFrame(frame);
|
||||
})(start);
|
||||
}
|
||||
|
||||
function play(){
|
||||
clearTimeout(countTimer); clearTimeout(moodTimer); cancelAnimationFrame(countRAF); stopFw();
|
||||
const target=parseTarget();
|
||||
const sad = target<=2;
|
||||
const t = sad ? 0 : Math.min(1, Math.log10(Math.max(target,3)/3)/3); // 5→0 … 5000+→1
|
||||
|
||||
// set mood + intensity
|
||||
stage.classList.remove('play','happy','sad','tier1','tier2','tier3'); body.classList.remove('sad');
|
||||
if(sad){ stage.classList.add('sad'); body.classList.add('sad'); }
|
||||
else{
|
||||
stage.classList.add('happy');
|
||||
stage.classList.add(t<0.34?'tier1':t<0.7?'tier2':'tier3');
|
||||
stage.style.setProperty('--grow',(1.12+t*0.16).toFixed(3));
|
||||
stage.style.setProperty('--halo-w',(160+t*70).toFixed(0)+'%');
|
||||
}
|
||||
|
||||
capEl.textContent=(capInput.value||'').trim();
|
||||
numEl.textContent='0';
|
||||
void stage.offsetWidth; stage.classList.add('play');
|
||||
|
||||
const sadS = Math.max(0, Math.min(1, (3 - target) / 3)); // 1→1 (most), 4→0 (least)
|
||||
|
||||
if(reduce.matches){ numEl.textContent=target.toLocaleString(); if(sad){ setTimeout(()=>sadFaces(sadS),0);} return; }
|
||||
moodTimer=setTimeout(()=> sad ? sadFaces(sadS) : celebrate(t), 2650);
|
||||
countTimer=setTimeout(()=>countUp(target), 2750);
|
||||
}
|
||||
|
||||
replay.addEventListener('click', play);
|
||||
numInput.addEventListener('keydown', e=>{ if(e.key==='Enter') play(); });
|
||||
capInput.addEventListener('keydown', e=>{ if(e.key==='Enter') play(); });
|
||||
window.addEventListener('load', ()=>setTimeout(play,180));
|
||||
</script>
|
||||
|
||||
<script>
|
||||
(function(){
|
||||
setInterval(() => {
|
||||
let isLight = false;
|
||||
try {
|
||||
isLight = !window.parent.document.documentElement.classList.contains('dark');
|
||||
} catch (e) {
|
||||
const p = new URLSearchParams(window.location.search);
|
||||
isLight = p.get('theme') === 'light';
|
||||
}
|
||||
window.isLightTheme = isLight;
|
||||
|
||||
if (isLight) {
|
||||
document.body.style.setProperty('background', 'transparent', 'important');
|
||||
document.documentElement.style.setProperty('background', 'transparent', 'important');
|
||||
const b = document.querySelector('.badge');
|
||||
if (b) b.style.setProperty('background', "url('/PragatiVeer_Logo/SVG_Logos/Square_light_background.svg') center/cover no-repeat", 'important');
|
||||
if (typeof fadeCol !== 'undefined') {
|
||||
fadeCol = 'rgba(255,255,255,0.22)';
|
||||
}
|
||||
window.sadFaceStroke = 'rgba(40,60,90,0.92)';
|
||||
window.sadFaceFill = 'rgba(40,60,90,0.15)';
|
||||
window.sadFaceEyes = 'rgba(40,60,90,0.95)';
|
||||
window.sadFaceTears = 'rgba(30,144,255,0.92)';
|
||||
} else {
|
||||
document.body.style.setProperty('background', 'transparent', 'important');
|
||||
document.documentElement.style.setProperty('background', 'transparent', 'important');
|
||||
const b = document.querySelector('.badge');
|
||||
if (b) b.style.setProperty('background', "url('/PragatiVeer_Logo/SVG_Logos/Square_dark_background.svg') center/cover no-repeat", 'important');
|
||||
if (typeof fadeCol !== 'undefined') {
|
||||
fadeCol = 'rgba(0,0,0,0.22)';
|
||||
}
|
||||
window.sadFaceStroke = 'rgba(182,200,228,0.92)';
|
||||
window.sadFaceFill = 'rgba(150,175,210,0.13)';
|
||||
window.sadFaceEyes = 'rgba(205,218,238,0.95)';
|
||||
window.sadFaceTears = 'rgba(150,205,244,0.92)';
|
||||
}
|
||||
}, 100);
|
||||
})();
|
||||
</script>
|
||||
|
||||
1
public/vercel.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1155 1000"><path d="m577.3 0 577.4 1000H0z" fill="#fff"/></svg>
|
||||
|
After Width: | Height: | Size: 128 B |
1
public/window.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill-rule="evenodd" clip-rule="evenodd" d="M1.5 2.5h13v10a1 1 0 0 1-1 1h-11a1 1 0 0 1-1-1zM0 1h16v11.5a2.5 2.5 0 0 1-2.5 2.5h-11A2.5 2.5 0 0 1 0 12.5zm3.75 4.5a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5M7 4.75a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0m1.75.75a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5" fill="#666"/></svg>
|
||||
|
After Width: | Height: | Size: 385 B |