diff --git a/frontend/public/saajan.png b/frontend/public/saajan.png new file mode 100644 index 0000000..7b0b00c Binary files /dev/null and b/frontend/public/saajan.png differ diff --git a/frontend/public/screenshots/e2e.svg b/frontend/public/screenshots/e2e.svg new file mode 100644 index 0000000..3dbaa10 --- /dev/null +++ b/frontend/public/screenshots/e2e.svg @@ -0,0 +1,102 @@ +

What stays on your device

What the server holds

PBKDF2 + Salt

wraps

stored as

encrypted with

produces

unwraps

recovers

decrypts

reveals

Your Password

Master Key
(never stored, never sent)

Letter Key
(unique per letter)

Wrapped Letter Key
(on server)

Your Letter

Encrypted Letter
(on server)

You open a letter

Your letter, readable.
Only here. Only now.

\ No newline at end of file diff --git a/frontend/src/components/Logo.tsx b/frontend/src/components/Logo.tsx index 0f470e2..33c9a4e 100644 --- a/frontend/src/components/Logo.tsx +++ b/frontend/src/components/Logo.tsx @@ -1,17 +1,33 @@ import { DotIcon } from "@phosphor-icons/react"; import "@fontsource/knewave/400.css"; -export default function Logo({ scale = 1, inline = false }) { - if (inline) { - // for span elements +interface LogoProps { + scale?: number; + type?: "inline" | "mono" | "logo"; +} + +export default function Logo({ scale = 1, type = "logo" }: LogoProps) { + if (type === "inline") { return ( - + Pi. Ku .  ); } + if (type === "mono") { + return ( + + pi. ku. + + ); + } + return (
+
+ + {children} + +
+ + ); +} + +export default function About() { return ( -
-
+
+ -
-
- - + + + + -
- -
+ -
- {/* zero knowledge */} -
+ + + + -
- {/* OSS - code source, contributions, attribution */} -
-
-
-
- -
- {/* Start Writing */} -
+
); } +function PrivacySection() { + return ( +
+

+ The   Promise + + privacy + + +

+
+

+ Your letters.{" "} + Nobody else's. +

+

+ When you write something here, it gets encrypted in your browser + before anything leaves your device. What reaches the server isn't your + letter. It's something unreadable — and the server has no way to + change that, because the key never left you. +

+
+
+
+
+

+ you see +

+ +

+ Your Password +

+

+
+ B@z1ng4A +

+
+
+ +
+
+ +

+ Your Letter +

+
+

Hello friend,

+

I've never told this to anyone...

+

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut + semper, justo eget vehicula vestibulum, enim enim suscipit + lectus, et sagittis nibh risus vel metus. Quisque eu ornare + ante, et gravida mauris. Vivamus massa justo, sagittis non + viverra sed, sodales non nisi. Nunc semper, massa a aliquet + dictum, enim nisi malesuada orci, et elementum lectus turpis + et velit. Nam vel felis vitae tortor dignissim malesuada. + Nam suscipit, justo eu elementum pulvinar, magna sem tempor + ex, vitae iaculis tellus odio non nisl. Duis dolor orci, + viverra ut finibus sed, aliquet vitae tortor. Proin sodales + ipsum ac ipsum hendrerit tempus. Nunc nec nibh nibh. Aenean + consequat auctor posuere. Integer sed magna volutpat, + efficitur nisl ut, dignissim neque. Vestibulum convallis nec + dui a euismod. Duis dignissim magna in mattis pulvinar. Sed + blandit nibh quis arcu ornare, sit amet fermentum nisi + rhoncus. +

+
+
+
+
+
+
+
+

+ server see +

+ +

+ Your Password +

+

+ 9e54d05f88bdd67a675b03bf1cd0a1647e2109b5aa18185ff6a9ba4c6959a19d +

+
+
+ +
+
+ +

+ Your Letter +

+
+

+ SZ0Mq9M9sCZsdDB8HGjk7JfWG56Kaot8Lgma74MCusDUYibUGoR7VviWgvc341pvFV9/IAyot9KtlDvwIX1ZmUw9Oh340JMaajRQ7iNgVjHgAwmJAr2cLbReNqlF6xzaf3mIYkiK9BXNQekk2h/9XufklsqoIXpaK1re7xWQ8mdddzy6z4EQFVH/Ev3np5ERW/ss7Z1kqYWUnANK7olWNL/7GgZmhU+L29rgbR52kcH9fng7gnEI3KEuISYExYCg81G1VaJYspkW3A4qwcet+jXdgmbKvkux5qNw6gyNi9d/YqKV7OUNrmoH190rHdJ5A7HOIv3/SvPhb3Zm4sNF5PcMxmhM0+T9m5PejV1GhV9bMBHbbgacay7hZJU3O0+q+7fBAE/+pqfvZdv78lLDFSdtHAXUpYOvHPrI5BNNwuS3T+FK1zjurLnUPThlOSYRICoZSUcxVswXz897PoRmFNNvbal0dpKUmCFrBwV5c/W3d1+iZor5msbm/JxpbNtys59e0StSTwHKsxvxm/rTuUAxWSOmzt13MDBxxd2zyVnX8rtQ7mEjMJ8IHHpvhKjONoa2S11VBJY68Ee1vNrw7htu+wajvmXhHAyfh1lYql8pu8VvPUG7leEQ9I0pMY35Y/C1cYCBLkDT5zf8NeZFtbp0BNgHd+QDVSFH+GSnvTskU2BCio3YE+zE6cDhvLUOMy3e5RAtPqsi5VzpEUcdCwph+Z+1pFlTxiEZ62i4wNpqw2lhS3b/E9ifJgnncSgRHLtfw/VxHZCRc4tBQ24xSZ507lSlQch+5lQeO7rx2htgd2D7aGNx/UN/xmeuEd4a28AxNOVS3uYh3wTDh8CSXyBRCRPxrANOV1ZBojdfK+v5fOJNPgDn3r5/pG80L3FTkecRB0zFuKNG8jIzi5ADx9k4SlhRNo17gPl2if8gRA6tzTae4kbzieG+woxhUWj/qvXg0MQmg59VTK2HHS34exdKDP9a561svlw+lJ2AtM1EL9srJk8i3kiyEPUeIlaLl3AfgbbSuC2RhlzFFAYuQ06rbsSvEoe4rrYeMXxL9jwVsXX0xrp8H25mOJu3ahn5pFYzADMSGf4L11H1vDArpefj/lW+8zcmogxxBktYYNF/qU4v+9367hp4MEn/84tQPpmb47TL+XpVnl9tQ3r9OfOaW3zX7NkWZbqoX7OgdgHOtTLP/euQujSs2MAzMO4BmbuCS7pR/GTZwDqF1sXiWAkunjo2qpKHieqlvSVmtwEhh6wsNwYTKEkddmTqvKSx0fHRvs3D9lMGJfg7wLSz/3Otx3G65tk9l/3B3r87qQTvbqXmcfnFdEIaR8mO/yMyCKnxtJkJb3lEzNUOrvnSxwL7Gyn54TLTWA== +

+
+
+
+
+
+
+
+
+ ); +} + +function SpecsSection() { + const [isModalOpen, setIsModalOpen] = useState(false); + + return ( +
+

+ S'more Specs +

+
+

+ uses{" "} + Zero Knowledge{" "} + + E + + nd  + + 2 + +   + + E + + nd + + +  E + + ncryption + + + {" "} + with{" "} + Envelope Encryption +

+

+ This means, both the encryption and decryption runs on your device, in + your browser. +
+ Every letter has a{" "} + unique key which is + derived from your original password. +
+ Both the letter and the key are encrypted securely and sent to the + server. +
+ Now, the server holds{" "} + the envelope,{" "} + the seal and{" "} + another locked box{" "} + with a key inside that unseals your letter. But you,{" "} + only you, hold the only + thing that opens the box —{" "} + your password. +

+

+ Nothing on the server is readable without your actual password. +
+ Even if someone were to breach in, all they'd find is encrypted noise. + +

+ + + + setIsModalOpen(false)}> +
+ pi ku e2e diagram +
+
+ +

+ This level of privacy comes with a catch.{" "} + No password reset. +

+

+ Your original password is never stored + on the server. Which means if it's lost, the letters stay sealed + forever. +

+
+
+ ); +} + +function OSSSection() { + return ( +
+

+ + only for +
+ your letters + +
+ is{" "} + +  private + {" "} + open source ! +

+
+

+ is fully open source. Every claim about privacy + and encryption is publicly available in the code so you don't have to + take anyone's word for it. +

+

+ You can also{" "} + Self-host{" "} + in just 4 steps. +

+
+
+            git clone https://git.ramvignesh.dev/me/pi-ku.git
+          
+
+            cd pi-ku
+          
+
+            ./scripts/setup.sh
+          
+
+            ./scripts/start.sh
+          
+
+ +
+ + View on GitHub + +

+ Found something to report or request?{" "} + + Please say so. + +

+
+ +
+ +

+ Built on the shoulders of open source. +

+ +

+ wouldn't exist without the work of people who + chose to build in the open. +

+ +

+ + Web Crypto API + {" "} + — the backbone of everything promised. Browser-native + cryptography that runs entirely on your device. Without it, none of + the privacy here would be possible — or credible. +

+ +

+ + DaisyUI + {" "} + ·{" "} + + Fabric.js + {" "} + ·{" "} + + Phosphor Icons + {" "} + — the beautiful work by others that let me focus on the core + experience. +

+ +

+ Open source is what made this possible. It felt right to give it back + the same way. +

+
+
+ ); +} + function StorySection() { return ( -
+

-
+
பின் after @@ -83,11 +444,11 @@ function StorySection() {
-
+
குறிப்பு note. remark. @@ -132,22 +493,34 @@ function StorySection() { "max-w-200 md:text-xl p-6 flex flex-col gap-4 md:gap-8 text-base-content/70 leading-relaxed" } > -

- pi. ku. is - an abbreviated transliteration of the Tamil word for{" "} - +

+ is an abbreviated transliteration of the + Tamil word for{" "} + P -

@@ -158,16 +531,18 @@ function StorySection() { change the subject.
Those words{" "} don't just disappear. They {" "} - stay unsaid — a - quiet weight difficult to bear. + stay unsaid{" "} + — a quiet weight difficult to bear.

And that's okay...

- pi. ku.{" "} + was built for putting that weight down. @@ -182,23 +557,337 @@ function StorySection() { function ForWhoSection() { return ( -

+
+
+

+ Who is
this for? +

+ +
+

+ wasn't built for one kind of person, but a + particular kind of feeling — + + {" "} + the one that lingers very quietly + {" "} + — fragile, yet never breaks. +

+ +
+ + See if any of these feel too familiar to you + +
+ +
+
+
+
+ +
+
+ ); +} + +function ArchetypesSection() { + return ( +

- For Who + The Archetypes

-
-
-

+
+
+
+ + {" "} + To someone you can't reach anymore. + +
+

+ A person who left. A relationship that ended without a real + ending. Someone who's still in your life but will never know + what you felt. Some conversations just close before they're + finished. +
+

+

+ Write the letter anyway. Keep it close. +

+
+
+ + 01 + +
+ +
+
+ + {" "} + To someone who's still here. + +
+

+ Not every letter is about distance. Sometimes you just need to + say something properly — without a text thread, without + the noise of a conversation already in motion. A letter slows it + down. +

+

+ Give people their due flowers while they can still smell them. +

+
+
+ + 02 + +
+
+
+ +
+ {" "} + +
+ To yourself, further along. +
+
+

+ Not a journal. Not a note-to-self. A proper letter — to + whoever you'll be in a year, or five, or ten. +
+ Ask yourself of the healed wounds, forgotten fears, or the + things you finally learned to live with. +

+

+ Set a date and let a letter surprise you when you've long + forgotten writing it. +

+
+
+ + 03 + +
+
+
+ + {" "} + For liberation. + +
+

+ Some unsaid words just need to leave your headspace. There's no + recipient, no subject line, no send button. Just the act of + putting it somewhere outside of yourself.
+ That's sometimes enough. +

+

+ Say it once. All of it. Then let it fade. +

+
+
+ + 04 + +
+
+ stamp +

+ If any of these felt familiar, +
+ no matter how little, +
+ this is for you. +

); } + +function AttributionSection() { + const [hover, setHover] = useState<{ + visible: boolean; + x: number; + y: number; + }>({ visible: false, x: 0, y: 0 }); + + const navigate = useNavigate(); + + return ( +
+ {/* Saajan hover image */} + + {hover.visible && ( + + )} + + +

+ Honest Speak +

+
+
+ Hi. +

Thank you so much for making it this far. Really.

+

+ took a while to exist. +
+ This started as a{" "} + + CS50W + {" "} + capstone, one I kept postponing until I ran out of reasons not to. + When I eventually sat down to build, I knew it had to be more than a + deadline; it had to be something that outlasted the grade. I wanted + to create a space for the feelings we usually keep to ourselves and + every hour spent on it was worth it. I've shared the edges of{" "} + here, but the heart of it is best found by + exploring it yourself. +

+

+ I kept coming back to{" "} + + setHover({ + visible: true, + x: e.clientX, + y: e.clientY, + }) + } + onMouseMove={(e) => + setHover((h) => ({ + ...h, + x: e.clientX, + y: e.clientY, + })) + } + onMouseLeave={() => setHover((h) => ({ ...h, visible: false }))} + > + Saajan + {" "} + from{" "} + + The Lunchbox + {" "} + —{" "} + + one of the most subtle yet brilliant portrayals by Irrfan Khan + {" "} + — the quiet emotional weight he carries throughout the film, + going through the motions of a lonely life, until those letters + arrive and something inside him finally loosens. Of course, the + ending felt like a deep sigh of "it is what it is". But something + about the act of writing and letting the unsaid out eased it, even + briefly. I think about that a lot. +

+

+ There's a lot that goes{" "} + + unsaid + {" "} + now. Not that people feel less or for the lack of time, but because + the ways we reach each other have quietly changed. We're always + reachable digitally, yet somehow the + things that matter most end up staying inside. +
+ Maybe writing will help with that. Maybe something about putting + words somewhere deliberate makes them feel less like something + you're carrying. +

+

Or maybe it won't, but it's worth a try.

+

+ is for that try. I hope it helps. +

+

+ — Ram +

+
+
+ "I think we forget things if there is nobody to tell them." + + ~ Saajan Fernandes, The Lunchbox + +
+
+
+ +
+
+ ); +}