JARS
JARS is an interactive web app where text messages come alive through physics. Letters from a message float in a jar — press Enter to let them scatter and fall with gravity, press Escape to animate them back into place. The home screen rains down a shower of jar images you can drag and fling before clicking one to enter.
Features
- Physics-driven text — Each character in a message is an independent Matter.js rigid body that responds to gravity, collisions, and mouse interaction.
- Enter / Escape controls — Press
Enterto release letters into freefall; pressEscapeto smoothly tween them back to their original positions. - Interactive jar rain — The home screen spawns hundreds of jar sprites that fall and stack; drag them with the mouse, click one to open a jar.
- Create a Jar modal — Name a new jar and optionally add an initial message.
- Login modal — Credential form with Google OAuth placeholder.
- Responsive layout — Adapts jar count and text sizing for mobile vs. desktop.
- Pixel / serif typography — Four custom Google Fonts (Pixelify Sans, Instrument Serif, DM Sans, Courier Prime).
Tech Stack
| Concern | Library |
|---|---|
| UI framework | React 19 |
| Build tool | Vite 6 |
| Styling | Tailwind CSS v4 |
| Physics engine | Matter.js 0.20 |
| Icons | Lucide React |
| Language | TypeScript 5.8 |
Project Structure
src/
├── App.tsx # Root — screen router + modal state
├── main.tsx # ReactDOM entry point
├── index.css # Tailwind v4 theme + custom keyframes
└── components/
├── HomeScreen.tsx # Landing page shell
├── HomePhysicsWorkspace.tsx # Matter.js jar-rain canvas (home)
├── JarScreen.tsx # Individual jar view shell
├── PhysicsWorkspace.tsx # Matter.js letter-physics canvas (jar)
├── CreateJarModal.tsx # "New Jar" form modal
└── LoginModal.tsx # Login / Google sign-in modal
└── ...
Component overview
App.tsx — Owns the two-screen navigation state (home | jar) and the open/close state for both modals. All navigation and modal callbacks are prop-drilled from here.
HomeScreen.tsx — Renders the full-screen layout: a pixel-font login button top-right, a jar image with a "Create a Jar" button in the centre, and the HomePhysicsWorkspace canvas behind everything.
HomePhysicsWorkspace.tsx — Sets up a Matter.js Render + Runner pipeline. Spawns jar sprites at randomised positions above the viewport with staggered setTimeout delays. Handles mouse drag via MouseConstraint and distinguishes a click (≤ 5 px drag) from a drag to trigger onJarClick.
JarScreen.tsx — The view of a single jar. Renders PhysicsWorkspace with the user message, a back button, date, time, and a keyboard-hint footer.
PhysicsWorkspace.tsx — Custom canvas render loop (no Matter.js renderer). Builds one circular rigid body per non-space character, positions them as centred text lines, and implements three modes:
static— bodies frozen at target positions.falling— bodies released as dynamic, gravity pulls them down.reviving— bodies tweened back to targets with a staggered per-line delay usingeaseOutCubic.
CreateJarModal.tsx — Controlled form with jar name + initial message fields..
LoginModal.tsx — Login modal with a Google sign-in button.
Getting Started
Requires Node.js 18+ and pnpm.
Install dependencies
pnpm install
Run the dev server
pnpm dev
Opens at http://localhost:3000.
Production build
pnpm build # emits to dist/
pnpm preview # serve the built bundle locally
Type-check only
pnpm lint # runs tsc --noEmit
Update packages
pnpm update # updates every package availabale in node modules to its latest
pnpm update -i # to view a menu and selectively apply available updates
---
## Keyboard Controls (Jar screen)
| Key | Action |
|---|---|
| `Enter` | Release all letters into freefall |
| `Escape` | Animate letters back to their original positions |
| Mouse drag | Push / throw individual letters |
---
## Customisation
### Changing the demo message
Edit `displayMessage` in [src/components/JarScreen.tsx](src/components/JarScreen.tsx):
```tsx
const displayMessage = "Your custom message here.";
Adjusting physics feel
Constants at the top of src/components/PhysicsWorkspace.tsx:
const MOVE_DURATION_MS = 600; // tween duration when reviving
const INTER_LINE_DELAY_MS = 100; // stagger delay between lines
Theme colours
All design tokens are defined in src/index.css under the @theme block using Tailwind v4's CSS variable syntax.
Happy Coding and leave a star if you're stunned.