SA
Sohaib Ahmer
Live App ↗ Exit Project
PRODUCT DESIGN CASE STUDY • 2026
19TH MUMBAI INTERNATIONAL FILM FESTIVAL • JUNE 15-21, 2026

miffuser

A single-file Progressive Web App that puts the entire MIFF 2026 programme, 349 films across 7 days and 7 venues, in your pocket. Offline. Installed. No app store.

349
FILMS
1
HTML FILE
462KB
TOTAL SIZE
10
FILTER DIMS
0
DEPENDENCIES
PWA OFFLINE FIRST SERVICE WORKER SINGLE FILE DARK / LIGHT MODE LOCALSTORAGE NO FRAMEWORK PDF EXPORT
miffuser.netlify.app • Mobile Preview Mode
Open Fullscreen ↗
01 • PROJECT OVERVIEW

The constraint is the concept.

miffuser began with a single constraint: one file. No build toolchain, no CDN, no server. The entire festival programme, 349 films with schedules, descriptions, and catalogue images, lives in a single index.html that deploys to any static host and runs fully offline after first visit.

349FILMS
7DAYS
7VENUES
0DEPENDENCIES
462 KBTOTAL SIZE
02 • ARCHITECTURE

Single-file PWA stack

LAYER TECHNOLOGY NOTES
Data JS array literal 349 film objects parsed at startup, zero latency
UI Vanilla JS + HTML Direct DOM templating, no virtual DOM, no diffing
Styles CSS custom props Full dark/light system via :root token swap
Offline Service Worker Cache-first app-shell, all 349 images precached
Install Web App Manifest beforeinstallprompt, iOS and Android paths
State localStorage 11 keys: list, ratings, notes, priorities, settings
Export window.open + print Client-side PDF, no server, no library
Why no framework?

At festival scale (349 records, single-user, no real-time sync), a framework adds bundle size and complexity with zero benefit. Vanilla JS renders the full schedule in under 16ms. The constraint produced the architecture.

"What does a real MIFF attendee need on their phone at 9am, offline, queueing for Audi 1?"
That question shaped every feature decision, from Live Mode to package slot offset timing.
03 • SCHEDULE VIEW

The main interface.

INTERFACE ELEMENT

1. App Header & Live Clock

Icon, title, tagline. Live clock showing current time. Persists across all views.

REAL-TIME ENGINE

2. Live Now Toggle

Activates real-time mode. Filters to films currently screening or about to start. Refreshes every 60 seconds.

NAVIGATION

3. Day Tabs

One per festival day (Jun 15-21) plus All Days. Active tab in gold. In Live Mode, past days are hidden automatically.

SEARCH

4. Full-Text Search Bar

Full-text search across title, director, country, section, language, and venue. Composes with active filters in real time.

FILTERS

5. 10-Dimension Filter Panel

Opens 10-dimension filter panel. Badge shows active filter count when filters are applied.

STRUCTURE

6. Time-slot Header & Film Cards

Films grouped by screening start time. Title, exact screening window, package slot, venue tag, duration, country, section, director, language.

Live Mode Logic

The schedule clock drives every visible element: active day tab, time-slot visibility, and the "Ended" badge on each film card. Everything updates passively without a refresh.

04 • FILM DETAIL MODAL

Every film. Everything.

1. Drag Pill + Close

Bottom-sheet indicator. Dismisses on tap outside or X. Android back button also dismisses.

2. Section Tag

Festival section in red. Always the first element, gives instant context.

3. Watched Toggle

Marks film as watched. Unlocks the post-watch thoughts notes field.

4. Metadata Tags

Country, duration, year, language as pill tags color-coded by type.

5. Catalogue Image

Official MIFF 2026 catalogue page crop with exact page number. Sourced from official materials.

6. Screening Schedule

All slots. Each row shows offset time, package window, venue, date, and an Add button for that slot.

Catalogue Image as Information

When no synopsis exists in the official catalogue, the scanned page replaces it. Attendees get exactly what MIFF published: nothing invented.

Screening-Level Saves

Saving a film saves the specific date, time, and venue slot, not just the title. A film screening four times requires a real decision.

05 • FILTER PANEL AND MY LIST

Curate. Save. Track.

# DIMENSION OPTIONS SAMPLE VALUES
01 Priority Mark 4 Must Watch, Priority, Good to Go, Unmarked
02 Section 30+ MIFF Prism, Short Comp, Animation Canvas, Best of Fest, Emerging Voices
03 Country / Language 55 / 74 Argentina to Vietnam. Ao to Without Dialogue, across 6 continents
04 Venue 7 Audi 1, Audi 2, RR III, JB Hall, IICT, SVKM, Ravindra Natya Mandir
06 • LIGHT MODE AND THEMING

Same app. Different light.

#1a1f3e
Navy Header / Base
#f0c040
Gold Active / Selected
#e8284a
Red Section / Danger
#7fc44c
Green Watched / Saved
#6a8cc8
Blue Venue Meta
07 • DATA MODEL AND PERSISTENCE

15 fields. Zero fetch.

Every film object is complete at parse time. No lazy-loading, no API calls, no spinner. The entire dataset is available the instant the JS executes.

KEY TYPE CONTENT
savedScreenings Object filmId::date::time → true
miff_priorities Object filmId → "must" | "priority" | "goodtogo"
miff_watched Object filmId → true
miff_ratings Object filmId → emoji rating level
miff_notes Object filmId → {{pre: string, thoughts: string}}
miffuser_mode String "dark" or "light"
miffuser_textsize String "small" | "medium" | "large" | "xlarge"
08 • DESIGN DECISIONS

The why behind the what.

Screening-level bookmarks

My List saves the specific date/time/venue slot, not just the film. A film screening four times requires a real choice. The bookmark is the commitment, not just the intention.

No invented descriptions

Strict data integrity rule: if the official MIFF catalogue provides no synopsis, none is shown. Catalogue page images are used instead. Attendees make real scheduling decisions from this data.

Independent filter state

Schedule and My List maintain separate filter contexts. Returning from a filtered My List to Schedule should never produce a view the user did not consciously set.

Back button = modal dismiss

Modal open/close is pushed to browser history. Android's physical back button dismisses the modal naturally. Double back-press on the main view shows an exit toast, matching native app behaviour.

Package slot offset timing

MIFF programmes short films in packages. "Film C" in a 2PM package might start at 2:18. miffuser calculates and displays the offset start time so attendees know exactly when to walk in.

Notes unlocked by state

"Thoughts after watching" is hidden until the film is marked Watched. Intentional friction: it makes writing post-screening feel like a meaningful moment, not a dead form field.

09 • ABOUT

Built by a filmmaker who needed it.

miffuser was designed and built by Sohaib Ahmer, a filmmaker and Master's student in Film & Video Communication at the National Institute of Design, Ahmedabad.

The project sits at the intersection of both fields: a deep understanding of how festival audiences navigate programmes, and the discipline to build a production quality PWA from scratch. miffuser was developed and iterated during the festival itself.

Launch Live App • miffuser.netlify.app ↗
MIFF 2026 • Jun 15-21, Mumbai