The official website of the Entrepreneurship Cell at RV University, Bengaluru:
a scroll-driven, shader-lit home for the startup community on campus.
Visit the site Β Β·Β Run it locally Β Β·Β Contribute Β Β·Β Deployments
E-Cell.Web.Demo.mp4
Most club websites are a list of links. We wanted ours to feel like walking into the room: you move your cursor and ink pours across the title, the logo draws itself and flies into the nav, the story scrolls sideways, and there's an arcade tucked in the corner for when you should be studying.
Underneath the motion it's a working site for students:
Flagship events like the Argonyx Hackathon, Winter Tech Talks and Talk Startup With Me, plus a full /events archive with filters, a calendar strip and a page for every event.
|
/recruit takes applications for PR, sponsorship, social media, design, photography, video, documentation and tech, and saves them straight to the team's sheet.
|
/opportunities points students to open hackathons, framed by an interactive globe.
|
A simulated WhatsApp chat answers the usual questions, then hands you a one-tap invite to the real group. |
| The team in a 3D card stack with a filterable directory, and past speakers in a circular carousel. | Every partner, from Nokia and Red Bull to the local bakery, mapped as a constellation that lights up as you hover. |
π«§ Liquid ink hero. Moving your pointer pours ink over a giant "ECELL RVU", revealing glass balloon letters floating in a particle nebula. On touch screens a blob wanders on its own until your finger takes over. The scene pauses when it's off screen or the tab is hidden, goes idle once the ink fades, and caps its resolution on big and small screens.
π A logo that draws itself. The brand mark is built from hand-tuned SVG paths, traced stroke by stroke as you scroll, then flies into the navigation bar and docks there. Click it to open a breakdown of the logo's geometry and meaning.
β‘ Laser light, written by hand. The community section glows with a custom GLSL shader: volumetric beams, drifting fog and noise, tilting gently toward your mouse.
πΉοΈ An arcade in the corner. Four small games, each fully playable:
| Game | The idea | |
|---|---|---|
| β¦ | Founder Sprint | Catch every spark before the clock runs out |
| π | Signal Snake | Classic snake, smooth controls, high score |
| π | Memory Match | Flip cards, find pairs, use as few moves as you can |
| π’ | 2048 | Slide and merge tiles with arrows or swipes |
π Scrolling that feels like butter. Lenis momentum scrolling, shared through one reference-counted instance so pages never fight over animation loops.
βΏ Calm when you need it. Every animation respects prefers-reduced-motion and jumps straight to its final state.
| Framework | Next.js 16 App Router Β· React 19 Β· TypeScript 5 |
| Styling | Tailwind CSS v4 and plain CSS kept next to each section |
| Motion | GSAP 3.14 + ScrollTrigger Β· Lenis smooth scroll |
| 3D | Three.js with custom GLSL shaders |
| Type | Archivo, Bebas Neue, Fraunces and Inter via next/font |
| Quality | Vitest + Testing Library Β· ESLint 9 Β· strict tsc |
| Insights | Vercel Analytics and Speed Insights |
| Hosting | Vercel through GitHub Actions Β· Cloudflare Workers through OpenNext |
You'll need Node 24 (pinned in .nvmrc) and npm 10+.
git clone https://github.com/ECell-RVUniversity/ECell-Web.git
cd ECell-Web
nvm use # or: fnm use
npm install
npm run devThen open localhost:3000 and move your mouse over the title.
All npm scripts
| Command | What it does |
|---|---|
npm run dev |
Development server with Turbopack |
npm run build |
Production build |
npm run start |
Serve the production build locally |
npm run lint |
ESLint across the project |
npm run typecheck |
Type-check everything with tsc --noEmit |
npm run test |
Run the Vitest suite once |
npm run test:watch |
Re-run tests as you edit |
npm run preview |
Build with OpenNext and preview in the Cloudflare Workers runtime |
npm run deploy |
Build with OpenNext and deploy to Cloudflare Workers |
Routes live in app/. Everything else lives in src/. Every homepage section is self-contained, so several people can work on the site at once without stepping on each other.
Sections own themselves
Each section in src/sections/<Name>/ carries its own component, styles and animations. No section leans on its neighbours' margins or layout, so any of them can be reordered or removed in app/page.tsx without breaking the page.
src/sections/Team/
βββ animations/
β βββ TeamAnimations.ts # GSAP for this section only
βββ components/
β βββ Team.tsx # 3D card stack
β βββ TeamDirectory.tsx # Filterable full roster
βββ styles/
β βββ Team.css
β βββ TeamDirectory.css
β βββ TeamLayout.css
β βββ TeamResponsive.css
βββ index.ts # app/page.tsx imports "@/src/sections/Team"
Content is kept apart from code. The roster, events, sponsors and links all live in src/content/, so updating the site rarely means touching a component.
One smooth-scroll instance, shared
src/utils/lenis.ts keeps a single Lenis instance with a consumer count. acquireLenis() starts it, and the release() it returns stops it. When the last consumer leaves, for example on a page with native scrolling, the instance and its animation loop are torn down cleanly.
GSAP registered once
Registering plugins in many files causes duplicate warnings during hydration, so src/utils/gsapSetup.ts does it once and everything imports from there:
import gsap from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";
gsap.registerPlugin(ScrollTrigger);
export { gsap, ScrollTrigger };The horizontal track
HorizontalFlow pins its container and turns vertical scroll into sideways motion:
const getScrollAmount = () => track.scrollWidth - window.innerWidth;
gsap.to(track, {
x: () => -getScrollAmount(),
ease: "none",
scrollTrigger: {
trigger: container,
start: "top top",
end: () => `+=${getScrollAmount()}`,
pin: true,
scrub: 0.8,
invalidateOnRefresh: true,
},
});When a nav link targets a panel inside the track, such as #speakers or #footer, a horizontal-flow:navigate event works out that panel's progress (index / total) and scrolls the window to the matching vertical offset.
Shaders and drawn strokes
- LaserFlow renders a full-screen quad. The fragment shader layers fractal noise, light falloff, converging beams and smoke wisps, and the mouse tilts it with damped easing.
- Stroke drawing: the
prepareSVGhelper setsstrokeDasharrayandstrokeDashoffsetto each path's exact length, then animates the offset to0so lines appear to be drawn by hand. - Kinetic type: words in the Story section are split into characters that wobble slightly as you scroll.
Performance and SEO
- WebGL scenes pause off screen and in background tabs, using
IntersectionObserveranddocument.hidden. - Animations stick to
transform,opacityandfilterso the browser never has to re-lay out the page. app/layout.tsxships Schema.orgWebSiteandOrganizationJSON-LD, plus OpenGraph and Twitter card metadata.- The manifest,
robots.txtandsitemap.xmlare generated fromapp/.
Full folder map
See projectmd/FOLDER_STRUCTURE.md for the placement rules.
ECell-Web/
βββ .github/workflows/ # CI, Vercel preview and production
βββ app/ # Routes and metadata only
β βββ events/ # /events archive and [slug] event pages
β βββ opportunities/ # /opportunities with the globe
β βββ recruit/ # /recruit application form
β βββ layout.tsx # Fonts, JSON-LD, metadata, analytics
β βββ page.tsx # Homepage composition
β βββ manifest.ts robots.ts sitemap.ts
β βββ globals.css
βββ public/ # Favicons, logos, og-image, _headers
βββ scripts/ # Cloudflare deploy wrapper
βββ src/
β βββ assets/ # Imported images (events, home, sponsors, teamβ¦)
β βββ components/ # Shared components, one folder each
β β βββ HalftoneWordmarkFooter/ CircularTestimonials/ EventsArchive/
β β βββ FloatingLogo/ GameLauncher/ HorizontalFlow/ InfiniteSpiral/
β β βββ LaserFlow/ LogoModal/ PageTransition/ RouteScrollManager/
β β βββ SiteCredit/ SmoothScroll/ Timeline/
β βββ content/ # Everything editable: team, events, sponsors, links
β βββ sections/ # Homepage sections
β β βββ About/ Events/ Hero/ Loader/ Nav/ Speakers/
β β βββ Sponsors/ Story/ Team/ WhatsAppCommunity/ WhyJoin/
β βββ styles/ # Global tokens and section transitions
β βββ types/ # Asset module declarations
β βββ utils/ # gsapSetup, lenis, scrollLock, math, cn, constants
βββ tests/ # Vitest suite, mirroring app/ and src/
βββ projectmd/ # Project docs
βββ next.config.ts open-next.config.ts wrangler.jsonc vercel.json vitest.config.mts
Vitest with Testing Library and jsdom covers routes and metadata, the events archive and event pages, the main sections (Nav, Speakers, Team, WhatsApp Community) including keyboard access, the arcade games, and the math helpers.
npm run test # once
npm run test:watch # while you work| Workflow | When it runs | What it does |
|---|---|---|
CI Β· ci.yml |
Pushes and pull requests to main |
npm ci β typecheck β lint β test β build, on Node 24 |
Preview Β· pr-cd.yml |
Pull requests to main |
Deploys a Vercel preview and comments the link on the PR |
Production Β· vercel-cd.yml |
Pushes to main |
Typechecks, tests and deploys to Vercel production |
| Cloudflare | By hand | npm run deploy, see projectmd/DEPLOYMENT.md |
Repository secrets for Vercel
Add these under Settings β Secrets and variables β Actions:
VERCEL_TOKEN: a Vercel access token with project permissionsVERCEL_ORG_ID: your Vercel organisation or user IDVERCEL_PROJECT_ID: the Vercel project ID
Students, club members and anyone who likes building things are welcome here.
- Read the contributing guide.
- Branch off as
feature/<name>orfix/<name>. - Keep your change inside your section. Talk to the team before touching shared styles.
- Make sure everything passes before you open a PR:
npm run typecheck && npm run lint && npm run test && npm run buildDesigned, built and looked after by the ECell RV University tech team:
![]() Akash Bisht |
![]() Akshay Sujesh |
![]() Shrisha |
![]() Aditya Dixit |



