6.7 KiB
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_eventposts + 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 afterevent_ends_atfundraiser— community fundraisingcurrent affairs— informational, reading, things worth knowing
layout: 2-column grid (FlatList numColumns={2}), 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_handlesetting: none / mutuals / all. contact_prefsfree 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_handlesetting.
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_handletoggle
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 react native, an open-source framework made by meta. 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)?