eutopic/docs/DESIGN.md

6.7 KiB
Raw Blame History

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 110 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)?