Every August, thousands of UF students buy dorm gear without knowing three things: will it fit, is it allowed, and who else is bringing one? A product page can't tell you whether a mini fridge fits beside your roommate's desk. UF's housing rules are pages of policy text. And the shared shopping list usually ends with two of everything.
We also kept running into a quieter problem: dorm rooms are small, sealed boxes that two people sleep in. Recent studies of university dorms have linked high overnight CO₂ to worse sleep, yet nobody planning a room ever thinks about air.
Our team spans computer science, mechanical engineering, civil engineering, finance and accounting. That let us attack the problem as geometry, policy, ventilation and money at the same time. DormU is the result. One room plan that answers all four questions before anyone spends a dollar.
What it does
- Pick your real room. A campus map of UF's 24 undergraduate halls opens 24 modeled room types. Every size is labelled Official (from UF's floor plans) or Estimated, and students can enter their own measurements.
- Design it in 3D. Drag furniture into a true-scale room built with React Three Fiber.
- "Can I bring this?" Paste a listing or snap a photo. Gemini reads it into dimensions, watts, amps and price, and SAM 3D Objects turns the photo into a 3D model scaled to those dimensions.
- The rules engine decides. 22 UF Housing rules run as geometry and limit checks, each citing its policy number. A tapestry one inch too high turns red with U.17.H. Our rule for the whole system: the AI extracts, the engine decides.
- Sleep and air. An overnight CO₂ estimate for the room, with door and window toggles and research-cited explanations.
- Budget and roommates. Sourced prices, a cent-exact split, and a summary texted to the roommate group chat through Twinly.
- Render my room and the Room report. Gemini's Nano Banana turns the 3D layout into a photo-style picture. A one-page report shows that picture next to every item's rule verdict, the air rating and the move-in total, ready to screenshot or print.
How we built it
The app is Next.js 16 + TypeScript + Tailwind, with React Three Fiber for the room, Zustand for state and MapLibre/OpenFreeMap for the map. AI runs only behind server routes: Gemini for reading items, SAM 3D Objects through Runware for meshes, and Nano Banana for renders. Every AI answer is validated with zod. Housing verdicts and money are never generated; they come from tested TypeScript.
The air model
The air model is a well-mixed mass balance. With CO₂ generation G, outdoor airflow Q=ACHV and room volume V:
$$ C(t) = C_{\text{out}} + \frac{G}{Q}\left(1 - e^{-Qt/V}\right) = C_{\text{out}} + \frac{G}{\text{ACH} \cdot V}\left(1 - e^{-\text{ACH} \cdot t}\right) $$
- CO₂ per sleeper: G10.0034 L/s, from Persily & de Jonge's tables at a sleeping metabolic rate of 0.95 MET, corrected to a 22 °C room.
- Outdoor CO₂: Cout=427 ppm (NOAA's 2025 Mauna Loa mean).
- Air changes per hour: ACH=0.32, 0.37, 0.82 for closed, door open and window open, the median values for each condition from 84 bedrooms in Fan et al. (2022).
For an Infinity Hall double:
$$ V = \frac{181 \times 139 \times 96}{1728} \approx 1{,}397.7\ \text{ft}^3 $$
With two sleepers over eight hours, the model reaches 2,210 ppm with everything shut and 1,180 ppm with the window cracked. Those are modeled numbers, not sensor readings.
We built the model in a spreadsheet first, wrote six test cases from it, and the app's code now matches the spreadsheet hour for hour. Ratings use the peak P:
$$ \text{good}: P < 1000 \qquad \text{stuffy}: 1000 \le P < 1400 \qquad \text{poor}: P \ge 1400 $$
The money
Prices are kept in integer cents, so a split always satisfies
$$ \sum_{i} \text{owed}_i = \text{total} $$
with leftover cents handled deterministically.
Testing
We tested each layer: 347 Vitest unit tests for the logic, and 53 Playwright browser tests at 1280×720 and on a phone. One of those tests opens every one of the 24 rooms and checks that the air panel appears.
What we learned
- Read the paper, not the abstract. Of the five "sleep and air" studies we had collected, only two actually measured CO₂ against sleep, and both were in university dorms. Every line in the air panel now cites the study that supports it, footnoted, and says "linked to," never "causes."
- Small rounding causes visible disagreements. Our spreadsheet rounded room volumes to whole cubic feet and the app didn't, so hourly values differed by 1 ppm. Judges notice when two numbers that should match don't, so we made both use the exact volume and wrote a test that fails if they ever drift apart.
- A realistic mesh is not a ruler. SAM 3D makes convincing objects, but size has to come from dimensions the student can check, never from the mesh.
- Shared contracts let five people build in parallel. Agreed shapes for items, air results and the split meant a mechanical engineer's spreadsheet could become someone else's unit tests overnight.
Challenges we ran into
- Turning policy text into geometry. "Nothing on the walls above the door frame" has to become a precise check on height, wall and position, with the policy number attached so students can verify our reading of it.
- Unreliable AI services. About one in three SAM 3D attempts failed, so we added retries, durable storage and pre-built demo models. Gemini needed tuning to stop timing out.
- A stale picture that only showed up on the second visit. Next.js 16 keeps recently visited pages alive in the background. Reopening the Room report showed the previous room's picture until we tied every image to a fingerprint of the exact design it was taken of. An AI render now steps aside for the 3D still the moment the room changes.
Built With
- fal.ai
- gemini
- gljs
- maplibre
- next.js
- openfreemap
- openstreetmap
- playwright
- react
- runware
- sam3d
- tailwindcss
- three.js
- twinly
- typescript
- vercel
- vitest
- zod
- zustland
Log in or sign up for Devpost to join the conversation.