u/SeaWingman

Visual timeline editor that exports plain motion/react JSX (free, MIT) — my first OSS project

I made this and I'm looking for feedback on the part that actually matters — the code it spits out.

Short version: it's a browser editor for landing-page hero text. You type a headline, select words to turn them into components, give each one effects on a timeline, scrub to preview, then export a single `Hero.tsx`. Free, MIT, no signup, no paid tier, nothing to install.

https://reactimate.top · https://github.com/shawnkowalchuk/reactimate

The design goal was that the output has to look like something a person wrote, not like generated code. So for a single multi-property effect it consolidates to one shared transition:

<motion.span

style={{ fontFamily: "Inter", fontSize: 96, fontWeight: 800, display: "inline-block" }}

initial={{ opacity: 0, y: 20, scale: 0.9 }}

animate={{ opacity: 1, y: 0, scale: 1 }}

transition={{ delay: 0.7, duration: 0.6, ease: "easeOut" }}

&gt;{"reactimate"}</motion.span>

and only drops to per-property keyframe arrays with `times` and a per-segment `ease` array when properties genuinely have separate timings or stacked effects. Text content is always emitted as `{"..."}` expressions so quotes and braces in the source text can't break the output.

One architectural decision I'd be interested in opinions on: **Motion is only used in the exported output, never in the editor itself.** Editor playback is a raw `requestAnimationFrame` loop writing styles directly to DOM refs, no React re-render per frame. That kept scrubbing smooth with per-letter stagger across dozens of spans, but it does mean the preview and the export are two separate implementations of the same semantics that have to agree — which is its own maintenance cost. I've wondered whether driving the preview with Motion's imperative API instead would have been the better trade.

Some things I know are rough: the editor is desktop-only right now, the bundle is chunky (~380 kB gzipped, code splitting is an open issue), and `spring`/`bounce` easings get approximated to `easeOut`/`backOut` on export because Motion's spring is a transition type rather than a curve and can't go into a multi-keyframe ease array.

So the actual questions:

  1. Does that generated code look like something you'd keep in your codebase, or does it read as machine output to you?

  2. If you were consuming this, would you rather it emitted a `<motion.span>` per word (what it does now) or a single parent with `variants` + `staggerChildren`?

Stack is React 19, TypeScript, Vite, zustand + zundo, Tailwind. Happy to go into any of the internals — it's my first open-source release, so critique of the repo itself is just as welcome as critique of the tool.

reddit.com
u/SeaWingman — 5 days ago

Making friends here as an expat — what actually works in a city this big

Bangkok paradox: ten-million-plus people and it can still be weirdly hard to build a real circle — everyone you click with lives 90 minutes away or leaves in three months. What's actually worked:

— Pick a schedule, not a venue. Run clubs, five-a-side football, climbing gyms, Muay Thai classes — same faces every week beats a great one-off night out. Repetition makes friends; one-offs make acquaintances.

— Gym or Muay Thai classes specifically: shared mild embarrassment bonds people faster than small talk ever will.

— Neighborhood over city. Pick your two or three BTS stops and be a regular there. More Bangkok friendships die to the commute than to anything else.

— Language exchanges and meetups: go to the same one three times before you judge it. First time you're a stranger, third time you're a regular.

— Coworking socials if you work remote — fastest way into the working crowd.

— Volunteering attracts the long-termers, the people actually invested in being here.

Full disclosure: I build a friendship app (SeaWingman — events-first, covers Bangkok), so weigh my bias — but everything above works with zero apps.

What's worked for the people who've been here for years?

reddit.com
u/SeaWingman — 7 days ago