# DESIGN.md — eutopic what the user experiences and why. not what gets stored (see DATA-MODEL.md). not stack decisions (see CONCEPT.md). --- ## design principles - users should never be asked to understand anything instagram doesn't ask them to understand. - friction is a feature when it slows down compulsive checking. friction is a bug when it slows down posting. - no dark patterns. no engagement optimization. no "one more thing" loops. - imperfection is intentional. DIY aesthetic over polish-as-performance. --- ## visual identity **status**: design collab in progress. nothing locked yet. **direction**: - wordmark only. no separate logomark — "eutopic" is distinctive enough as a word. - typographic register: considered, a bit odd, not startup-clean. something with character. - glyph set for nav icons to be developed as custom symbols, not system unicode or standard icon libraries. - aesthetic reference: zine, risograph print, hand-stamped, dingbat. not flat SaaS icons. - tool: figma. brief to follow from design collab. **nav icon candidates** (to be refined or replaced by collab): - home: ⒣ - posters: ⇶ - compose: ◲ - stories: ❣ - profile: ☺ these should ship as SVG assets or a custom icon font in the actual app — unicode rendering is inconsistent across android devices and system fonts. --- ## navigation five-slot bottom tab bar: ``` ⒣ home | ⇶ posters | ◲ compose | ❣ stories | ☺ profile ``` - **home** — chronological feed - **posters** — bulletin board (`/posters`, `is_event` posts + informational posts + fundraisers) - **compose** — center slot, filled/distinct treatment. opens compose flow (modal or full screen — TBD) - **stories** — dedicated tab, not a top strip. intentional destination, not ambient anxiety ring. - **profile** — own profile. viewing others' profiles navigates within the app but doesn't change the active tab. stories as a bottom tab (vs instagram-style top strip) is a deliberate choice: it frames stories as something you visit, not something that nags you to check. --- ## screens ### onboarding (unauthenticated) ``` invite gate └── invite code prefilled from deep link, or entered manually email + username entry magic link sent / confirm screen social handle opt-in └── signal / telegram / custom. skippable. "re-enable anytime in settings." follow suggestions └── friends-of-inviter auto-suggested. skippable. ``` zero technology decisions for the user. no server picker. no handle explanation. no fediverse vocabulary. --- ### feed (`/`) - chronological. no algorithm. no ranked content. - posts with 1–10 photos (swipeable within the post card). - reactions inline below each post. - comments accessible via tap (flat, chronological thread). - **survey card** injected at slot 1 when an active survey exists. GIF cover. taps to `/feedback`. disappears per-user once responded. not a real post. - no unread indicators. no "new posts" banner. pull to refresh is fine. --- ### posters (`/posters`) formerly "bulletin board". renamed because the scope is broader than events: **post types** (single tag, required, choose one): - `event` — dated gathering, auto-archives 1 day after `event_ends_at` - `fundraiser` — community fundraising - `current affairs` — informational, reading, things worth knowing layout: 2-column grid (`SliverGrid` / `GridView.builder`), infinite scroll, paginated fetch. filtering by tag: TBD (tab strip or dropdown above grid). reactions on poster posts: visible to post author only. no public counts. no hierarchy. RSVP interaction model: open question, not designed yet. see OPEN-QUESTIONS.md. --- ### compose (◲) - triggered from center nav slot. - photo picker first (up to 10 photos). - caption optional. - toggle: post to feed or post to posters. if posters: tag picker (single tag required) + event fields if `event`. - toggle: saveable on/off (default off). - toggle: reaction set — choose up to 5 emoji, or leave open (open picker only). - upload starts in background immediately on confirm. progress shown via hand-drawn animation. bad wifi handled invisibly via tus.io resumable upload. - no drafts, no scheduling, no queue UI. --- ### stories (❣) - dedicated tab, not a top strip. - 10s auto-advance per story. - filters via swipe gesture (basic, applied at view time or capture time — TBD). - no replies. "witnessed" metadata only: private per-viewer row, expires with story (24h). - story author can see flat witness list (like instagram). no public count. - story creation: camera or photo picker, then post. no drafts. --- ### profile (☺) **own profile:** - avatar, display name, username, bio. - social handles (signal / telegram / custom) — shown based on `display_social_handle` setting: none / mutuals / all. - `contact_prefs` free text ("bad texter", "weekends only"). - own posts grid. - settings access. **others' profiles:** - same view, minus settings. follow/unfollow action. - social handles visible per their `display_social_handle` setting. --- ### feedback (`/feedback`) - always accessible (settings link or survey card tap). - active survey renders at top if one exists (multiple choice, 36h expiry). - permanent free text field below, always present regardless of active survey. - no results shown to users. dev use only. --- ### settings + about **settings:** - account (username, display name, avatar, bio) - social handles (add / hide / remove) - contact prefs - `display_social_handle` toggle **about:** - "eutopic is a quiet place for friends to share photos." - "we don't track you. we don't run ads. we don't sell your data." - "we don't notify you — visit when you want to." - running costs (hosting, domain, apple developer program) — real numbers, updated manually. - liberapay donation link (opens in browser). - credit line: "eutopic uses flutter, an open-source framework made by google. we use their open work to build something they wouldn't." - "made with care in EU." no donor badges. no public donor list. donation is private. --- ## animations - upload progress: hand-drawn, DIY aesthetic. lottie or APNG. not a standard spinner. - reactions: subtle, not dopamine-optimized. no confetti, no burst animations. - transitions: simple. no parallax, no over-engineered motion. - imperfection is okay. "designed" imperfection is part of the identity. --- ## open UX questions see OPEN-QUESTIONS.md for live status. currently open: - compose: modal sheet over current screen, or full dedicated screen? - stories: filters applied at capture or at view time? - posters: tag filter UI — tab strip or dropdown? - RSVP interaction model (not designed yet) - comment hearts/likes — do comments get a reaction? tension with no-hierarchy value. - stories access: purely via tab, or also accessible from profile (own stories)?