Latest Posts (18 found)

Don’t be a scary old guy: My 40s survival strategy with charm

Hi, it’s  Takuya . Last week I had my birthday and turned 41 (November 19th). When I was younger, I could never really picture what life in my 40s would look like. It’s this vague age where you don’t have a clear image of how you’re supposed to live, right? Even if I try to look back at my dad at this age, he was always at work during the day, so he’s not much of a reference. I make a living as an indie developer , and thanks to what I built up through my 20s and 30s, I can live the way I do now. Compared to a typical Japanese salaryman, I can join childcare much more flexibly, and I get to spend a lot of time with my kid. I’ve even made some “mom friends (mama-tomo)” at kindergarten. In this post, I'd like to share my survival strategy for the 40s. As the title says, the conclusion is:  “charm”  — being warm and approachable. Let me explain why I think this kind of charm matters so much for middle-aged men. For students, guys in their 40s are full-on old dudes. At least that’s how I saw them. It’s basically the age of school teachers. When I hit my late 30s, people around me started to say things like: In Japanese,  kanroku  means something like “gravitas” or “presence.” And no, they didn’t mean my belly was growing. At first, I secretly thought: …but over time I realized that wasn’t it at all. It simply meant: I got older. In other words, “You’ve aged,” “You look older now,” wrapped in the most positive wording possible. I mean, think about it. What even is “aura,” really? lol If I’ve really built up so much life experience, why am I still getting scolded by kindergarten teachers for being late to the bus pick-up? It doesn’t feel like I’m walking around radiating some wise, dignified aura. Having gravitas doesn’t actually help you that much. If a middle-aged guy is frowning, shoulders slumped, walking around with a dark cloud over him, you just want to keep your distance, right? If you wrap yourself in charm instead, you can cancel out like half of that rough “old guy presence.” I used to work part-time at a café. When I asked the manager why he decided to hire me, he said: On YouTube as well, I try to make a smile in my videos. A smile is a key ingredient of charm. To cancel out this heavy “presence,” I want to be even more intentional about smiling and staying approachable in my daily life. If you just keep doing something for a long time, your achievements naturally pile up. And if you’re lucky, some of them end up being work that lots of people praise you for. But then one day you realize: The friends who used to argue with you freely and push back hard are suddenly keeping their distance. Indie dev is already lonely enough. But the more “achievements” you stack, the more your potential conversation partners quietly disappear. I read somewhere that Hirohiko Araki, the manga artist behind  JoJo’s Bizarre Adventure , once said that he’s become so successful and revered that people are now scared of him, and no one gives him advice anymore. It makes sense. If you imagine giving feedback to a famous author or legendary director, it feels terrifying, right? That’s why Araki-sensei apparently gets really happy when someone ignores that aura, doesn’t shrink back, and just casually says what they think. From what I’ve seen of him on TV and such, he seems full of charm. He smiles, teaches kids, and comes across as very gentle and kind. He’s a great example. If even someone like him still gets put on a pedestal and loses people to bounce ideas off, I absolutely have no business acting all high and mighty. The more serious and stern someone looks, the more powerful their smile becomes. That contrast is what makes it hit. In Japanese, we even have a word for this:  gap moe (ギャップ萌え) — the charm that comes from an unexpected contrast in someone’s personality or appearance. Take guitarist Eddie Van Halen, for example: When I picture an amazing guitarist, I tend to imagine someone completely lost in their own world, making intense faces while they play. But Eddie often turns to the crowd and smiles, clearly trying to entertain and enjoy it  with  them. That attitude is incredibly likeable. Programmers are a good example of a job that’s hard for people to picture. When mom friends ask what I do and I say: I often get: It’s not that they’re rejecting it; they just can’t imagine what I actually do, so they don’t know how to respond. The fewer shared reference points you have with someone, the more important it is to approach them with a soft, relaxed attitude. You don’t have to explain everything in detail. If they can at least feel that “he seems to enjoy his work and looks like he’s having fun,” that’s more than enough. So that’s what I want to value in my 40s. Lately, I’ve been feeling like younger people show me more respect than before. Precisely because of that, this is the time to  not  act superior, but instead live humbly and gently. I want to keep learning from younger generations and be inspired by them. I want to stay in touch with new values and cultures all the time. To do that, I have to break through the “gravitas” barrier myself. And I think charm is essential for that. If you’re around my age, what do  you  want to value in your life? I’d love to hear. Here’s to good 40s for all of us! Thanks for reading. Inkdrop is a Markdown-focused note-taking app for developers. It’s not about having tons of features — its strengths are the clean design and simplicity. If you’re looking for a clean and simple notes app, check it out: “You’ve got presence” just means “You look older now.” Make a smile. A grumpy middle-aged guy is just scary Be humble. The more achievements you stack, the more people shrink back Use the charm of contrast

1 views
Takuya Matsuyama 3 weeks ago

My plan to avoid hyperfocus and keep a healthy work pace (as a dad of two)

Hi, it's Takuya here. As I wrote in my previous post , I recently pushed myself too hard with my indie SaaS dev work and ended up burning out. One of the main reasons was my tendency to hyperfocus. When I get absorbed in something, I tend to lose sight of everything else — sometimes even my personal life. To avoid repeating the same mistake, I’ve decided to redesign how I work. As a freelancer and indie developer, I have full control over how I spend my time. That’s a double-edged sword, where I can work as much as I want, but there’s no one to stop me when I go too extremely. My wife works in a different field, so she can’t really tell how intense my work pace is. If I say I’m tired, she’ll tell me to take a break, but she doesn’t interfere with how I manage my time. That means I can’t rely on anyone else to pull the brakes — I have to be my own guardrail. (Though I’m considering to have a therapist to get some professional perspective regularly.) It feels great to organize your day down to the minute — I used to love that. But now, with my second daughter recently born, keeping a perfectly structured schedule just isn’t realistic. So instead of sticking to rigid time blocks like “15 minutes of X after waking up,” I’m choosing flexibility. As a father of two, I need to adapt my day around the family’s rhythm. After burning out, I realized how crucial health is. Now in my 40s, I can’t rely on youth anymore. If I want to keep doing indie development for as long as I can, I need to prioritize health and stamina. I’ve had atopic dermatitis for years, and I’ve noticed it improves when I walk a lot. Luckily, my legs are fine, my eyes work, and my hearing is good — so I’ve decided to make 10,000 steps my daily goal. Walking also helps my mental state — it relaxes me, sparks new ideas, boosts serotonin, and improves sleep. So my rule is simple: if the destination is within 30 minutes, I’ll walk. So, I’d like to go places on foot if the destination is within 30 minutes. In the mornings, I walk around the park and head to a café in the next town. I even go to the supermarket on foot instead of by bike. From experience, I’ve learned that if I don’t hit 5,000 steps by noon, the afternoon gets tough — pacing matters. Playing with kids or filming videos both require physical strength. So I do light strength training daily. Here is my typical routine: Morning routine: Before bed, I add: There’s no deep reason behind these numbers — it’s just what feels sustainable. Also, excercise helps distract me from itching when my skin flares up. With the basics set, let’s plan out how I spend my day. After dropping my daughter off at kindergarten, I start by walking around the park to take in the season — about 2,000 steps. After dropping my daughter off at kindergarten, I start by walking around the park, taking in the sights and sounds of the season — about 2,000 steps. Then I grab my laptop or iPad mini and walk 15–20 minutes to a café (usually Starbucks). Cafés are great for creativity, because the people, the sounds — they make me feel connected to the world. Even a short chat with the barista can lift my mood. So in the mornings, I focus on marketing tasks, content ideas, or just free exploration. No strict plans — I follow my curiosity. Reading a book would be also nice. I'd like to work on tasks that require focus and energy in the afternoon, like coding, customer support, and other tasks that need deep concentration. Home is the best place for that. I can sing out loud if I feel like during the tasks. I usually work until around 5 p.m., when my daughter gets home from preschool. Sometimes I wrap up early to take a short walk — it helps cool my head before family time. I don’t want to bring that “wired” energy into the evening. I’m in charge of cooking, so I make dinner — usually something simple based on what I feel like eating. I try to keep it to one soup and one dish, a meal style called Ichiju-issai(一汁一菜). Both cooking and grocery shopping help me unwind and prevent hyperfocus. Right before I burned out, what I lacked most was mental space. I poured all my energy into app development and had no time to pause and reflect. So now, I’m setting aside one day a week to do things unrelated to the app — basically, a day off. Weekends are for family, so I’ll take a solo day off during the week — probably Wednesday for now. But I’ll stay flexible. This day is like watering a plant — giving myself time to breathe. It’s fine to do nothing at all. I might go on a short day camping trip, visit a museum, or just watch videos and read. Looking outward like this helps prevent tunnel vision and burnout. Development isn’t everything — I’ve always dedicated about half of my time to marketing anyway. So overall, the weekly balance won’t change much. What does “development pace” mean in the first place? I’d rather release high-quality updates at a sustainable rhythm than rush something out while feeling anxious and narrow-minded. This is all about building a lifestyle that lets me keep doing this long-term. Ultimately, my app users will decide if it works or not. I’m building a note-taking app surrounded by big competitors. As an indie developer, I can’t win by competing the same way large companies do. The key is to find areas they wouldn't do — to differentiate by not fighting the same battles. That requires keeping my mind open and constantly exploring new things. My wife is still in the hospital as of this writing, and I am in the midst of a chaotic one-person parenting situation. Also, since it will be a special operation even during my family visit, I cannot spend my days as described above. However, the most important thing is to work at a healthy pace and to enjoy doing it while maintaining mental and physical health. If I can maintain that, anything is fine. I should be flexible. Thanks for reading. Inkdrop is a Markdown-focused note-taking app for developers. I’ve been developing it for over eight years now. If you’re looking for a notes app, check it out: 50 push-ups 20 dumbbell curls 20 shoulder presses 10 scap raises 50 leg raises (abs) 100 back extensions

3 views
Takuya Matsuyama 1 months ago

How low self-esteem and hyperfocus drove me to burnout

Hey, this is Takuya . Recently, I pushed myself too hard on indie development and ended up sick , as I posted a video on my channel recently. My atopic dermatitis flared up badly, and my quality of life dropped sharply. It was like hell, literally. I’m still recovering, but I’ve been walking more than 10,000 steps every day and slowly getting better. To make sure I don’t repeat the same mistake, I wanted to dig into why I tend to overwork myself. Mental health in indie development isn’t something people talk about much, so maybe this reflection can help someone who’s been in the same situation. It’s been around eight years since I started living solely off the app I built. People often call it a dream lifestyle — making a living from something you created yourself. And yes, I’m truly grateful for it. But behind the freedom and independence lies a quiet loneliness and a constant fear that no one will catch you if you fall. My app is a note-taking app, and this market is brutally competitive — a red ocean. The fear of losing users to competitors is always there, gnawing at the back of my mind. The reason I’ve kept going so obsessively with indie development comes from one deep, personal experience. Back in college, I hit a dark period when my relationships suddenly started falling apart. Friends turned cold or rejected me, I was emotionally shaken, and things with my parents got worse too. I felt worthless — like I didn't deserve to exist. Depressed. Even so, I somehow kept making little tools and uploading them to my website. One day, someone left a message on my site: That single line shook me to my core. I originally started programming because I wanted to make an action RPG like The Legend of Zelda . Since development tools were scarce back then, I had to build everything — the map editor and character designer. Through that, I learned how to make Windows apps and eventually created small tools like a P2P file transfer app and an automatic mp3 tagger . I kept doing this quietly throughout college. When someone said “thank you” to me for something I made, it was literally life-changing. It made me realize, maybe I do have value. No one around me — not even my parents — really understood what I was doing, but that one message gave my life meaning. On the surface, that sounds like an inspiring story. And it was. But it didn’t solve my deeper problem: a lack of self-esteem. That experience gave me a conditional sense of self-worth — I only felt valuable if my users appreciated what I built. If not, I felt meaningless. My happiness was in other people’s hands — I was dependent on users’ approval. The bar was very very high. If my work didn’t gain attention, I sank into emptiness. And when it did gain attention, it faded quickly. There’s no lasting self-esteem in that loop. So I kept pushing harder, chasing that feeling of validation again and again. My early success in indie development ironically became fuel for an unhealthy drive. It sounds kinda extreme, right? 😅 I think that’s because of one of my innate traits. As I mentioned, I used to make games. I’d come home from school, eat dinner, and then stay glued to the computer — coding, composing, drawing sprites. One day my mom asked me in a serious tone, “Why do you have to work that hard?” And I didn’t have an answer. My head was just full of things I felt I needed to do, and I couldn’t think about anything else. It was an insane solo challenge to build a full action game, and by the time I realized it, I was already graduating high school. (Side note: before my high school entrance exams, my parents actually hid the keyboard so I wouldn’t use the computer. 😆) I don’t have ADHD, but once I get focused on something, I become tunnel-visioned. Even when I’m exhausted, I tell myself, “Just until it compiles,” or “Just until I fix this bug.” When I’m deep in code, I do ridiculous things — like walking into a closet thinking it’s the bathroom, or biking to the gym and walking home, forgetting the bike entirely. If you’ve had similar experiences — take it as a warning sign, not a bragging right. This trait of mine definitely strengthened my belief that “I’ll only be happy if I succeed in indie development.” This overfocus clearly harms my health, but it’s not something I can just “fix.” It’s like a character in an RPG with severely unbalanced parameters. Or a system where, once you issue a command, you can’t change it for ten turns. That’s just how I’m wired. I have no choice but to accept it. So I decided to treat this trait as an unfixable bug in my system. There’s an interesting idea in evolutionary medicine. Thoroughbred racehorses are bred for speed, but their bones became so thin and fragile that about one in a thousand races ends with a broken leg. As writer Akira Tachibana puts it, perhaps our highly specialized minds — optimized for creativity or intelligence — come with the same kind of fragility. It’s just an analogy, but it resonated with me. I may have a talent for building apps, but it came with the cost of this extreme focus. If I know from the start that I’m “a car with great acceleration but weak brakes,” then I can plan around it. A lack of self-esteem is a deep, complex personal issue. To fix my unhealthy motivation, I need to reframe that core experience — to accept that “I’m a valuable person whether my app succeeds or not.” And sure, I’ve read enough books to know this intellectually, but knowing it in your head and truly believing it in your heart are very different things. Because that old “thank you” message was such a powerful memory that it still defines my sense of worth. So, it seems that learning to accept myself unconditionally might be a lifelong process, which would be something I’ll gradually get better at with age, or maybe finally understand right before I die. Maybe re-living my childhood through raising my kids will help heal those old wounds and fill that missing piece of self-esteem someday. Even though I lack self-esteem, when it comes to indie development, I somehow stay incredibly optimistic. No matter how hard I work on an app that ends up flopping, I don’t stay down for long. I always think, “Well, I’ve done my best. Yoroshiku-onegaishimaaaasu! (Whatever happens, happens!)” and release it. If it fails, I just analyze what went wrong and move on. When I remind myself of that, even failure feels like data — something to learn from, not fear. This post itself is an experiment too: “What happens if I talk openly about mental health?” — let’s find out. Even though overworking made me sick, it also forced me to pause and reflect deeply on my life. While enduring the relentless itch from my dermatitis, I’ve been thinking about video ideas and how I want to structure my comeback week. I’m planning to write another post about how I plan to work after recovery. You might think that after all this pain, I’d want to quit indie development altogether — but no, not at all. As I said, I’m still an optimist. If I truly couldn’t handle it, I’d have gone back to freelancing long ago. But when my body started showing warning signs, I’d already lost sight of the joy in working on the project. I was obsessed with competition, anxious about the user churn graphs, and couldn’t stop thinking about the app even in bed. I wasn’t resting properly. One big reason was the fear that if I stopped developing, users would abandon me immediately. But when I finally gathered the courage to announce a break, I received messages like this: After reading these comments, I realized that I should not set a "deadline" to get recovered, as it can be another pressure that hinders my healing from atopy. So, I've decided to drop the return date and fully focus on getting better. Thanks you so much for your kind words!!!!🙏 pic.twitter.com/Zi5RqsSeZR @philocoder said: @brendanaw said: The community’s response was overwhelmingly positive — not a single “Inkdrop is dead” comment. Instead, most people said, “Take a proper rest!” That really moved me. As I rested, I felt my mind settling down, and my perspective widening again. I’ll write another entry about how that rest changed me mentally and physically. Life is long. Don’t die over app development! In this article, I looked back on my past to understand why I tend to overwork myself. Did any part of it resonate with you? What early experiences shaped your motivation to work? I’d love to hear your thoughts in the comments. Thanks for reading. Inkdrop is a Markdown-focused note-taking app for developers. I’ve been developing it for over eight years now. If you’re looking for a notes app, check it out: Looking back on my roots How coding gave me a reason to live My formative experience gave me an unhealthy motivation Seeing it as an unfixable bug in my system Accepting myself just as I am, regardless of the app’s success Why I haven't given up: I’m basically optimistic, despite it all My users told me to rest – with no 'deadline' Life is long. Don’t die over app development!

0 views
Takuya Matsuyama 1 months ago

The scariest “user support” email I’ve ever received

Hi, it's Takuya . As your app grows in popularity, you occasionally start to attract attacks aimed directly at you—the developer or site owner. Just the other day, I got one that was honestly terrifying, so I'd like to share it. In short, they’re saying: Weird already — because my app’s website, https://www.inkdrop.app/ , doesn’t even show a cookie consent dialog . I don’t track or serve ads, so there’s no need for that. Still, I replied politely: A bit later, I got this reply (which Gmail had automatically placed in the spam folder): At first glance, it looked perfectly normal. But notice — they never actually told me which page was causing the issue. Instead, they sent a link claiming to contain a screenshot. It looked like a Google Drive link, but it was actually a Google Sites page. Without thinking, I clicked it. (You should never do this!) It showed a Captcha screen. I clicked it… and got this: It said something like “verification step” — telling me to open a terminal, paste a command, and run it. That’s when it hit me: “Oh no, this is phishing.” The command they had copied to my clipboard was this: Never run anything like this in your terminal. It downloads and executes a shell script from a remote server — as ChatGPT confirmed when I asked it to analyze it: Absolutely terrifying. Because Gmail had flagged the second message as spam, the URL was probably already reported as malicious. But the first message wasn’t flagged — so I thought, “Maybe it’s a false positive,” and replied. Big mistake. Even on my user forum, I’ve started seeing suspicious posts that seem to be written by AI. They look natural at first glance, but the intent is unclear — often just spam or trolling. Phishing emails disguised as support inquiries are getting more sophisticated, too. They read naturally, but something always feels just a little off — the logic doesn’t quite line up, or the tone feels odd. It’s unsettling. Stay alert, guys — the attacks are getting smarter. Hope it's helpful!

0 views
Takuya Matsuyama 1 months ago

Discovering the joy of driving as a long-time paper driver

Hi, it's Takuya . Ever since I got my driver’s license before entering university, I had basically never driven a car. Living in the city, I avoided driving as much as possible. The thought of operating something that could seriously hurt or even kill someone if I made a mistake honestly scared me. But a few things changed that — I got married, moved back to Osaka, had a kid, and got interested in the outdoors. Around Osaka, there are many nice places for short drives — Minoh, Nose, Kobe, Tamba-Sasayama, and so on. So, little by little, I started renting cars through Times Car Share and nervously began driving again. The first thing that surprised me was this: every other car on the road is also driven by a real person . That might sound obvious, but it actually felt like a fresh realization. In games like Grand Theft Auto , the cars are just NPCs — they move clumsily, crash into you, and never react intelligently to what you’re doing. But in real life, everyone’s trying not to crash. Drivers read each other’s movements, make space, and take turns. Sure, there are rude drivers sometimes, but as long as no one makes a huge mistake, things usually go smoothly. If I accidentally start going the wrong way, someone honks to warn me. When I let another car cut in, they flash their hazard lights to say thanks. That kind of human interaction — something you’d never get in a game — is surprisingly fun. Cars are such an integral part of Japanese society that enormous time and money have gone into building our road system. It’s thanks to all that effort that we now have such a comfortable network of highways and streets. As a working adult, I’ve been paying taxes for years — and part of those taxes has gone into maintaining this infrastructure. So when I drive, I feel like I’m finally getting to enjoy the benefits of what I’ve helped build. Of course, buses and taxis also use the same roads, but driving yourself gives you far more freedom. As I glide along these perfectly paved roads that spread like arteries through the country, I can’t help but feel impressed by how well they’re maintained. When I mostly got around on foot or by train, I never paid attention to cars. But once I started driving, I found myself noticing different models and brands. Even though modern cars tend to look a bit similar, there’s still a surprising variety out there. I used to only hear about Tesla in the news, but now I’ve actually looked up prices and read owners’ reviews. I’ve also discovered that I really like models like the Mini — cars that keep their classic design but update it with modern specs. That said, I probably won’t buy one until I move to the suburbs — maybe when I build a house someday. Owning a car in the middle of Osaka would feel like a luxury. In terms of skill (and courage), I got much better during my daughter’s summer vacation. Her kindergarten stops its bus service during summer, so if we wanted her to go to daycare, we had to drive her ourselves. Since my wife’s work schedule didn’t match, I became the driver, using a car-share vehicle to take her each morning. At first, driving through Osaka city on weekday mornings was terrifying. I made tons of mistakes — missed lanes, took wrong turns — and felt completely drained afterward. I was also shocked by how many one-way streets there were. Seeing the city from a driver’s perspective made everything look different. But as I learned the routes and got used to the flow, I started driving calmly and confidently. Before long, I could go on other trips without getting nervous. Those morning drives to kindergarten were honestly the best training I could’ve asked for. In recent years, I’ve gotten into outdoor activities — checking out campsites in the suburbs, or taking short drives to places like Minoh, Lake Biwa, Tamba-Sasayama, or Kawachi-Nagano. I never imagined that adding “driving” to my list of transportation options would change my daily life and mindset this much. I’m not saying everyone should go out and start driving, especially if they’re firmly against it. But if your life feels a bit stuck in a routine, maybe it’s worth giving it a try — you might find a new kind of freedom waiting for you.

0 views
Takuya Matsuyama 3 months ago

Zen: Why Inkdrop never extends Markdown syntax

I've been running Inkdrop , which is a Markdown note-taking app, and I’ve decided to never implement proprietary Markdown extensions, as that’s the philosophy of the app. The strength of Markdown (specifically GitHub-flavored Markdown) lies in its status as a widely used, loosely standardized document format in the software industry. If I were to add app-specific syntax, the notes you write would instantly lose compatibility with other Markdown tools. You might think, “Adding proprietary syntax could enable more convenient features.” And indeed, Markdown isn’t a perfect format, so there are cases where extensions seem necessary—like the lack of a standardized way to specify image sizes, for example. Still, I’ve prioritized the portability of notes above all else. Behind this choice lies a philosophy rooted in Zen (禅). Japanese culture tends to blend with, adapt to, and coexist with its surroundings rather than confront them. This is evident in concepts like Shakkei(借景/borrowed scenery) in windows, kare-sansui (枯山水/dry landscape gardens), the asymmetry of architecture, the simplicity of tea rooms, and the aesthetic of wabi-sabi. Let me explain with the example of the “subtractive brush” technique (減筆) in painting. This method involves using minimal brushstrokes to depict forms on silk or paper. Zen painters have used this technique to express psychological landscapes. For instance, take Wagtail on a Lotus (蓮に鶺鴒図) by Mokkei (伝 牧谿): A solitary bird perches on a withered branch. Not a single unnecessary line or shadow is drawn, yet it fully conveys the desolate feeling of autumn. In this way, the canvas’s empty space is fully utilized, with only the bare minimum of elements added. The Eastern perspective sees life from within, not from the outside. This contrasts with Western art, which often expresses transcendence over harsh nature through gorgeous and rich magnificence. Inkdrop embodies this Zen spirit, seeking harmony and collaboration with Markdown and its surrounding ecosystem of tools and platforms. I want the notes you write in Inkdrop to flow outward and return, allowing your ideas and sensibilities to expand and be refined. I aim to support this lifecycle. In fact, from a business perspective, introducing proprietary syntax might allow me to lock users in (vendor lock-in), which could be advantageous in the note app market. However, looking at other apps that have adopted proprietary syntax, it’s clear that this often leads to complexity, difficulty in learning, or struggles with syntax conversion. For an indie developer like me, half-hearted extensions would do more harm than good. I think that sticking to compatibility and harmonizing with the Markdown ecosystem ultimately benefits the app. As a result, it’s a win for the app creator, the users, and the ecosystem —– this is a concept known in Japan as "sanpo-yoshi" (三方よし/three-way satisfaction), from the philosophy of Omi merchants (近江商人). For these reasons, Inkdrop has not and will not extend Markdown. I promise. So, feel free to take your technical notes with confidence! That's the philosophy of Inkdrop. Join the v6 canary testing now 🙌 🎬 Watch Video Version

0 views
Takuya Matsuyama 4 months ago

Inkdrop v6(canary) is now available 🥳 The new Markdown editor and more

Hi! This is Takuya. I'm super excited to announce that the first canary version of v6.0.0 is available 😆✨ It comes with a bunch of ground-up improvements. Let's go! Release notes: In v5, the toolbar was fixed on top of the editor, which takes up the space even when you don't use it. Instead, the editor now displays a floating toolbar when selecting text. The editor now supports highlighting Alerts with the proper colors and left border. It even works with nested alerts and quotes. Also, it provides a autocompletion to assist entering the alert type. In an empty line, pressing shows up a list of available insert commands such as blockquote, heading, and alerts. When you edit code in a codeblock, autocompletion automatically gets enabled, depending on a supported language. By inputting and first two characters, it shows GitHub-styled emoji candidates: When you press ```, it suggests available supported languages: When you press , you can search for a note to insert as an internal note link. It previews the selected note content. A command palette has been one of the long-awaited features. On the other hand, the built-in search bar has become more popular for utility apps these days. So, I decided to build a versatile search bar, inspired by other macOS's Spotlight-like tools like Raycast, that can search multiple types of sources at the same time. This feature is called Telescope (yes, the name was borrowed from telescope.nvim !) For example, it supports the following sources: Press Cmd/Ctrl-K or select View → Toggle Telescope from the application menu to launch Telescope: Then, just type some keywords. It supports fuzzy-matching, so you don't care about spelling so much. Each source may have a scope prefix like and . They let you quickly narrow down items with the associated scope. For example, when you wanna search only commands, press > + Space. Press Esc to clear the scope. Most operations in Inkdrop are defined as commands. You can execute these commands by dispatching programmatically . Telescope allows you to dispatch a command without using the API. It also displays associated shortcut keys on the right side of the command items if available. The next powerful Telescope source is notebooks. It allows you to not only open the selected notebook but also open as Workspace , and move the current note to the selected one by pressing Enter with a modifier key as indicated at the bottom of the bar. The Tags source helps you navigate notes through tags. This source is interesting. When you are writing a long-form blog article, you may want to jump around section titles. This source lists the sections of the editing note. You can quickly jump to the selected section from it. Pretty neat, huh? On top of that, it also displays task items! It would be helpful to manage todo lists in the notes. Telescope is extensible by design, too. You can add custom sources freely. I can't wait to see what source you will add! It migrated to the modern build pipeline based on Electron Builder, which allows to support Flatpak and AppImage for modern Linux distros. Looking forward to hearing your thoughts and feedback 😆 Let's build an awesome Markdown note-taking app together. Thank you so much for your support, as always ❤️ Table of contents of the editing note 👉 Join the canary testing

0 views
Takuya Matsuyama 4 months ago

Agentic coding made programming fun again

Hi, it's Takuya . I have a 9-year-old SaaS with multi-platform desktop and mobile apps called Inkdrop , a plain-text Markdown note-taking app. Recently, I started using Claude Code in my project. My first attempt was a failure , though I eventually got used to it in my workflow. Then, I recently realized that app development had become fun again. It was unexpected. So, I'd like to share how I adopted agentic coding in my workflow and how it changed my perspective on indie app development. 🎬 Watch Video Version As you might imagine, maintaining such a long-lived product is super hard. In the early days, adding new features was a breeze, and everything felt speedy. However, each time you increase the amount of code, your software grows exponentially more complicated. This means you accumulate a lot of technical debt as your product grows. My Electron app imported a large part of the code from the Atom Editor to accomplish flexible customizability and high extensibility. So, I managed to quickly provide a comprehensive set of features required for a text editor, even though I am a solo developer, by standing on the shoulders of giants. It was a similar approach to Cursor , a fork of VSCode, for a recent example. However, Atom was unfortunately sunset in 2022. Since then, many dependencies of my app have stopped being maintained. This has been a huge headache for me in keeping my product going. Because replacing obsolete libraries is totally not fun, and besides, it doesn't provide additional value for users. The amount of required workload seemed too large for me alone. I nearly gave it up... Then, recently, Claude Code and other AI CLI tools emerged. This changed the game entirely for such a long-running product. Let me share how I got into the AI tools. Since everyone was praising AI tools, I assumed it should be easy to adopt for an experienced developer. But I was wrong. About a month ago, I tried using Claude Code to build a simple tool, but failed miserably. I tried a one-shot prompt to build a complete project. Claude Code kept generating wrong code, broken code, and unexpected code. I realized that without careful prompts, context management, or deep oversight, vibe coding could easily lead to dysfunctional code. Let's say riding a bicycle looks simple and easy, but it actually requires you to practice. So do AI Agents. Here's what I learned from feedback in the comments (Thanks): And I've read some articles: In the next attempt, I successfully built a RAG tool for myself with Claude Code! Since then, I've often been using Claude Code as my coding assistant, like an intern developer. The key to using AI Agents I realized is: Motivation. It helps you stop procrastinating on boring tasks. As mentioned, AI is pretty good at doing tasks that many people have done in the past. If there is a boring task such as boilerplate, small automation, legacy code, or one you don't care to write by hand, AI can solve it pretty quickly and neatly. And I found myself feeling so good after finishing these tasks using AI. It frees up my working memory. I have fewer headaches. So, in my case, I had too many boring but inevitable tasks to do due to the deprecation of the Atom Editor. For example, there are two important parts: These two parts depend on each other. So, I had to migrate them at the same time. Feeling down – I had been procrastinating on that. However, I won't explain the details here, but I managed to replace the old ipm with a modern and simpler implementation, and managed to replace the bloody complex custom build pipeline with Electron Builder by letting Claude Code analyze it, plan the migration steps, and create boilerplate. For example, here is an analysis and migration plan that Claude Code created: This helped me a lot to grasp the overview of the work. There was some old and misinformation in it, but I could fix it by letting it read the docs. This was a life-changing experience for me. Some people say AI is useful and some people disagree – I think that's because they don't understand its characteristics. AI generates code so fast that you might think coding is no longer a bottleneck, then reviewing it becomes a new bottleneck. This is a common misunderstanding of AI. Think of AI as a bullet train. You can get to popular cities pretty fast. However: You only have a few seconds to enjoy Mt. Fuji from Tokaido Shinkansen. You still have to transfer to a local train, bus, or taxi to visit specific places. Similarly, AI tools don't let you: You can't understand the process of why AI ended up generating the result code. Especially if you are not familiar with the language the AI outputs, it is impossible to understand the details. To improve the quality, you still have to fix minor errors, adjust spacing, wording, and refactor the code structure. You will notice that those who over-praise AI tools do just what AI tools are good at: Get you to a popular place like a bullet train. People who dislike AI tools try to see Mt. Fuji closely from a bullet train, which is impossible as well. Since AI is just a tool, like Shinkansen, you still need other tools or manual coding to make exactly what you want. So, our bottleneck hasn't changed: Your creativity and craftsmanship. No matter how AI gets smarter, our organic skills always matter. I'm excited about this. While letting AI do chores and boring tasks, I can enjoy adding new features and implementing novel things that AI doesn't know yet. What do you think? Looking for a Markdown note-taking app designed for developers? Check it out: Don't go in blindly – plan well: Define a detailed spec and break it into small deliverables . Tackle one task at a time. Use unit tests to verify each part before moving on. Ask Claude to help craft prompts as well—prompt engineering matters. Vibe coding works best when: Used for boilerplate , small automation , legacy code , or tasks you don't care to write by hand . You treat Claude as a helper or worker , not as a lead developer. Don't replace yourself – augment yourself: The better you understand what you're doing, the less vibe coding you'll want to do. AI is good at execution , not intuition . Use it to speed up, not take over. Start with a clear structure: Begin with a todo list or roadmap. Separate work into phases : e.g., scaffolding → features → tests → polish. Manage expectations: AI struggles with: Large or complex codebases. Fine-grained control over behavior. Non-standard tools or stacks (e.g. Bun + SQLite). Field Notes From Shipping Real Code With Claude - diwank's space How I Use Claude Code | Philipp Spiess Claude Code is My Computer | Peter Steinberger Agentic Coding Recommendations | Armin Ronacher's Thoughts and Writings ipm - Inkdrop Package Manager. Originally forked from apm . Build pipeline : While most recent Electron apps use Electron Builder or Electron Forge , Inkdrop was still using its own custom build pipeline originally from Atom. You can't enjoy the views closely from the train because it's too fast You can't get to the exact place you want to go, but just to the large hub stations look into details that AI generated because it's too fast create the exact thing you imagine because it can't infer your thoughts perfectly

0 views
Takuya Matsuyama 4 months ago

How to automate signing your Windows app with Certum's SimplySign app

I’ve been running a SaaS for 9 years, which includes an Electron app for Windows. For code signing, I’ve been using Certum's Code Signing Certificate: The pricing has been great, but there’s been one small annoyance that makes automation a bit tricky. In this post, I’ll share how I worked around it. Certum uses an app called SimplySign to handle authentication. This app is required for signing but unfortunately makes it impossible to automate the code-signing process out of the box. By default, SimplySign Desktop isn’t connected: You need to manually double-click the tray icon and enter a TOTP (Time-based One-Time Password): The code is generated by their mobile app. This manual step breaks automation because, without completing it, you can’t use — the private key isn't loaded until SimplySign authenticates. While setting up SimplySign, you scan a QR code to activate your account: It turns out that this QR code contains a standard URI. You can scan it with other password managers like 1Password — and indeed, 1Password shows the exact same token as the SimplySign app. When you click the Edit button, you can reveal the underlying URI. This means you can generate the token programmatically using a script! Here’s a PowerShell snippet that generates a TOTP using inline C#: This alone gives you the token. Now, let’s use it to automate the authentication step. PowerShell can simulate keystrokes sent to a window. This snippet searches for the SimplySign Desktop window and, if found, sends the TOTP code via simulated keystrokes. Here’s the full PowerShell script you can use to automate the entire process: You’ll need to define these environment variables: I keep these in a file and use to load them when running the script. I hope this helps you automate code signing with Certum and SimplySign! Looking for a good Markdown tech note-taking app? Here is what I'm building:

0 views
Takuya Matsuyama 5 months ago

How to automate development journaling with Claude Code

Hey, what's up? This is Takuya . I recently started using Claude Code to write code. It works great with my tmux and neovim setup since it can run as a CLI tool. It dramatically improved my productivity, but I tend to get lost in what I was working on and what I finished because the AI agent works so fast. This is exactly why I started automating my development journaling using Claude Code with my note-taking app, Inkdrop . In this article, I'll show you how to set up an AI-powered journaling workflow that keeps track of your work automatically. Before we dive into the automation, let me quickly introduce Inkdrop – it's a simple Markdown note-taking app designed specifically for developers. Think of it as your digital notebook where you can organize your thoughts, document your learnings, and keep track of your projects using clean Markdown syntax. What makes Inkdrop special for developers is that it understands our workflow. It has syntax highlighting for code blocks, supports math expressions, and lets you organize everything in a hierarchical notebook structure. Plus, it syncs across all your devices with end-to-end encryption, so your notes are always secure and accessible. Journaling is crucial for remembering what you've accomplished and what you learned. Here's the thing – when you're in the vibe-coding zone, things progress so fast that you easily forget what you worked on. One moment you're debugging a CSS issue, the next you're refactoring a component, then suddenly you're implementing a new feature. By the end of the session, it all becomes a blur, even if you manage your code with git repositories. Manual journaling is too slow in vibe coding. You may already wanna work on the next task when finishing a task. This is where AI-powered journaling shines. The magic happens through MCP (Model Context Protocol) integration. If you're using Claude Desktop, you can follow this guide I wrote earlier: Integrating my note app with Claude's MCP . The setup is pretty straightforward. You'll need to: The neat thing about Claude Code is that the MCP configuration is project-specific, so you can have different setups for different projects. This allows the AI to read from and write to your Inkdrop notebooks seamlessly while working on your code. You can instruct Claude Code to write a journal at the end of each task. Create or update file in your project root (or adding this to your existing Claude instructions) with the following prompt: This structure gives Claude Code a clear framework to follow. The AI will automatically: You can directly specify your note ID by using the dev-tools plugin, which helps you quickly copy IDs via context menu: I worked on building a simple RAG system for my Inkdrop notes in this video, and tried automating journaling in this session. Please check it out! It's interesting to see the AI agent try to take tech notes while coding. I guess it should be also possible to automate tech note-taking for manual coding. I'll keep exploring the possibilities with the AI agent! Set up Inkdrop's local HTTP server by following the official guide Install the MCP server package globally : Configure Claude Code by creating or updating your project's file: Start Claude Code in your project directory, and it will automatically load the MCP server configuration from your file. Create a new journal entry for each coding session Document the specific prompt or task you gave it Explain what it accomplished Detail the approach it took Note any challenges encountered Suggest future improvements

0 views
Takuya Matsuyama 7 months ago

What I did for upgrading React Native to 0.79.1 from 0.74.2

Hi, it's Takuya here, the developer of Inkdrop – a Markdown note-taking app that supports syncing and offline-first capabilities, built with React Native. Bumping up the React Native versions has always been hard, and this time wasn't an exception, especially because it involved migrating from the old to the new architecture . So, I'd like to share what I did for this upgrade. As reported here, Xcode 16.3 removed the base template for . This change prevents to build iOS app. So, I could't build my app with React Native 0.74 since it is out of the support window. So, I had no choice but to upgrade React Native. My first step was to visit the React Native Upgrade Helper , which provides diffs between your current version and the target version. The diffs in my case looked simple. I manually applied them to my project. After that, I ran into this error when building the app: I deleted the file and ran again. Then, it solved. My app has a custom native module for supporting PDF export from an embedded webview. I shared how to get an instance of the native view components in a custom module here: Since then, there have been some breaking changes in internal modules, so I updated the code accordingly. On Android, is now deprecated. Here is the new approach: On iOS, the way to get the object has been changed like so: In the sidebar, wasn't working correctly as seen in the screenshot above. I had to add in the prop like so: The app stores data using PouchDB and SQLite as its backing store. For a SQLite adapter, I use op-sqlite . There was a breaking change when upgrading it from v6 to v12. To get it to work as before, you have to change the method as the following: I made a small contribution to fix a bug in the crypto library: I've published a PouchDB adapter for SQLite and shared it in this article: This adapter has been broken on the recent RN versions, so I updated it. This PR helped me do so (Thanks Gufeng Shen): I've tested it on my app and it worked fine, so I publishded it: In RN 0.79, some navigations didn't work for some reason. Maybe this was due to nested navigators. I found that using solved it. It lets you get the root navigation regardless of the context. You can use it like so: For more information, check out the docs: https://reactnavigation.org/docs/navigating-without-navigation-prop/ After updating RN, App Connect started sending this warning when submitting the app: I greped the source and found that the React Native core uses it: However, my app doesn't use APNs and looks already deprecated. Maybe I can ignore the warning: If there are any ways to avoid this warning, please let me know 🙏 That's it! Most issues were app-specific, but I hope it's helpful. The new architecture is much more stable than before thanks to the community's effort. Also, it feels like very performant like the faster launch speed. I will keep focusing on the app quality for providing a great note-taking experience! [🐛] IOS store submission warning for ITMS-90078: Missing Push Notification Entitlement after upgraded to Expo 51 · Issue #7896 · invertase/react-native-firebase

0 views
Takuya Matsuyama 7 months ago

How to animate a TanStack Virtual list with motion (rev. 2)

The desktop version of my note-taking app is built with React and Electron. Previously , I managed to animate the insertion and removal of specific items of a TanStack Virtual list using motion . However, that approach would always trigger animations whenever the note list content changed, including when switching notebooks from the sidebar. Ideally, the animation should be triggered only when the data itself changes . I've finally got it to work, as demonstrated below: 0:00 / 0:02 1× From vlog: https://youtu.be/9J9cL_VyLRY This feature is now available in Inkdrop Desktop v5.11.2 ! 🥳 I'd like to share how I achieved this in this article. In React Native, there is an API called , which schedules an animation to happen on the next layout. I guess my app could take a similar approach to conditionally trigger animations in the note list. So, the rendering flow would looks something like this: With this approach, list items are rendered as regular elements instead of and the list container don't wrap them with when the database doesn't have any new changes. When scheduling an animation, it re-renders the whole list and items to invoke motion's animations. Well, doesn't it affect performance? – Why TanStack Virtual is performant is that it only renders visible list items in the current viewport and scroll position. In my app, it would be typically around 5-10 note list items at a time. So, I assumed that it would be fine. In your note list item component, you can switch the component like so: In your list component, you can conditionally wrap/unwrap the content with depending on the animation flag like so: This depends on your app stack and implementation. In my case, I added a hook to watch database change events and schedule an animation via Redux dispatch: After finishing the animation, the flag gets disabled again. That's it! I hope it's helpful to add a smooth list layout animation to your app 😃

0 views
Takuya Matsuyama 8 months ago

How I implemented TOTP-based 2FA for my Markdown note app

Hey, what's up? This is Takuya. I'm building a Markdown note-taking app called  Inkdrop . As of v5.11.0, it supports two-factor authentication with a time-based one-time password. Thank you so much for the feedback during the beta testing! In this article, I'd like to share how I implemented this feature. My case is a bit different from typical cases because my app supports end-to-end encryption (E2EE) for its data sync across devices and platforms. So, it can't simply rely on any IAM (identity and access management) platforms like  Auth0  to authenticate users because they don't natively support E2EE mechanisms. They only have the responsibility to deal with credentials on your behalf securely. But this is not a big problem. There are a lot of libraries that let you support 2FA. A time-based one-time password (TOTP) is a temporary passcode generated by an algorithm that uses the current time of day as one of its authentication factors ( ref ). It is a commonly used method for two-factor authentication, and perhaps you may have already used it on other web services. I've tried several libraries ––  speakeasy  looked like the most popular choice but it is no longer maintained.  otplib  and  node-2fa  looked promising, but the last commit dates of them were 4 years ago.. 🤔 I saw that some articles published recently used these libraries without mentioning their last update dates. Is this normal? Maybe that's because these libraries are simple enough, but I was nervous to rely on these old libraries in production. Then, I came across time2fa: The maintainers are from a company called PlanetHoster, one of the hosting services. I looked into the repository. This library has zero dependencies, which is nice. It is written in TypeScript. Good. The docs looked adequate. And most importantly, the source code looked simple, so maybe I can maintain it myself just in case if it is abandoned in the future. So, I decided to go with time2fa. It is super easy: You should store   in your database. As you can see, it doesn't require any external services to implement TOTP. Many websites provide backup codes in case you lost access to your second factor device. These codes are a single use only. time2fa supports generating backup codes: However, these look not so secure as they are just 6-digit numbers. Instead, I implemented one that generates codes with the GitHub-style like so: To implement UIs for setting up 2FA, I used v0 to get some inspiration. You can view my v0.dev mocks here: It generated the first page like this: I didn't use the generated code because v0 naturally ignored my request on using Semantic UI but it used Next.js and TailwindCSS. Just for inspiration. Here is the second-page mock: Alright, it looks good. I've implemented UIs like so: The next step is to implement the login screen. Here is the v0 mock: Here is my implementation for the desktop app: And the mobile app: I've created a custom OTP input that consists of 6 input bars. I've shared the code snippet on Inkdrop here: Note that My UIs are implemented with Restyle . Hope this helps for building your SaaS! 🙌 Prompt : Create a page for enabling two factor authentication with TOTP that displays a QR code and an input for testing passcode generated with user's authenticator app. I'm using React and Semantic UI. Do not use supabase or any PaaS, just for static UI for mocking. Prompt : ok, next, create a result page for after successfully enabling the 2FA .

0 views
Takuya Matsuyama 8 months ago

Answering dev questions based on my tech notes using MCP + Claude

In the previous post, I integrated my note-taking app Inkdrop with Claude's MCP: I've updated the MCP server for Inkdrop , which has got the following new tools: Vlog is also available: I've been exploring practical use cases of MCP with Inkdrop. I've got some questions from my audience: So, he would like to know my thoughts on using CouchDB, PouchDB, and Electron for building offline-first apps. I usually don't answer these personal questions since I simply don't have time for it, but this time, I thought it'd be interesting to generate answers with Claude and my MCP server, based on my tech notes stocked in my Inkdrop database. Let's try it. First, I tried to check if Claude is aware of my knowledge via MCP: Then, Claude summarized my related notes by automatically thinking of keywords to search. Cool: There is an official plugin that allows you to quickly copy a note ID, notebook ID, and tag ID via context menus: It was originally meant to help develop plugins but it's also useful for specifying a note or notebook to AI. I used it to tell Claude which note to read and update. Claude viewed the specified notebooks and successfully created answers based on my knowledge. Here is the result: I think it is not perfect but good enough to make content. I hope it's helpful to get ideas for using the MCP integration! : List all notes in a specified notebook. Required inputs: : The notebook ID. It always starts with 'book:'. Optional inputs: : An array of tag IDs to filter. Each starts with 'tag:'. : Keyword to filter notes. : Sort field ( , , or ). Default: . : Reverse the order of output. Default: . Note: Results include truncated note bodies (200 characters). Use to get full content. : Retrieve a list of all tags.

0 views
Takuya Matsuyama 8 months ago

Integrating my note app with Claude's MCP

Hi, it's Takuya here. I've been fiddling with Claude, which provides an interesting protocol for third-party AI integrations called MCP (Model Context Protocol). Some of my note app (called Inkdrop ) users requested that they want to let Claude use their tech notes as knowledge via MCP. Yeah, that sounds very interesting, so I tried to support it. MCP itself is a pretty simple protocol and there is already a TypeScript SDK, so you can quickly start implementing it: The Claude desktop app invokes MCP servers locally to interact with external data or services. MCP can accept data via stdio or SSE (HTTP). Inkdrop supports running an HTTP server locally so you can programmatically access your notes. It allows you to access via MCP as well. For example, to let MCP clients to read a note in the Inkdrop database: Pretty simple! I've published a repository and npm package for Inkdrop: Let me know what you will do with this integration! That's it! I hope you enjoy it 😄 Set up a local HTTP server Add server config to Claude Desktop: MacOS:  Windows:  Can you find my reading notes about a book called "Four Thousand Weeks" in Inkdrop? Then, can you create a new note to summarize these notes in the notebook "Blog"?

0 views
Takuya Matsuyama 9 months ago

How to animate a TanStack Virtual list with Motion

I love Motion . It makes animating UIs in web apps incredibly easy. I've been using it in my app to animate components like the tags input bar, the notebook list, dialogs, and more. One of the components I wanted to animate was the note list. This was challenging because the list can be long, and its items have variable heights depending on the content. Recently, I migrated the note list from react-list to TanStack Virtual because it seemed more versatile and performant for recent React versions. However, I couldn't find any concrete guides on animating the insertion and removal of list items, so I decided to tackle it myself. In this article, I'll share a tip on how to animate list item insertion and removal using TanStack Virtual and Motion. First things first, check out a quick demo here. I've forked the official dynamic example and modified a few lines. A quick demo animating removal of one of the list items In this demo, the second list item is removed two seconds later with an animation. The list contains 10,000 items but shows no performance regression. The technique is simple: wrap each item with like this: The state is updated in a hook for the demo: With this approach, you need to know beforehand which items have been added or removed, depending on your app's implementation. Why should you wrap list items individually, instead of wrapping the whole list? That was my initial approach, but it broke the list, causing issues like this: The issue was that items weren't properly unmounted due to the use of the prop in , as I demonstrated in the vlog: 0:00 / 0:08 1× TanStack Virtual optimizes rendering performance by only rendering items that are in the viewport, unmounting items that scroll out. This behavior conflicts with , which watches for changes in its child elements, leading to unintended animations. By wrapping each item individually, you avoid these issues and ensure smooth animations when inserting or removing items. That's it! I can't wait to apply this technique to my app 😄

0 views
Takuya Matsuyama 9 months ago

How I efficiently built a browser extension

I've released a new browser extension for Inkdrop last week. The previous version was built several years ago, and the codebase had become outdated. I decided to rebuild it from scratch since I was planning to add a new feature: importing Kindle highlights. I managed to complete the rebuild in just a week. I'm 40 but my coding speed is not quite bad I think because I managed to rebuild a browser extension from scratch with a new feature in a week, while preparing for tax report and going buying kindergarten entry supplies for my daughter. Here are some small tips on how to build a browser extension efficiently. Setting up a browser extension project with hot-reloading, TypeScript, bundling, and generation is annoying. While you can clone a popular extension template from GitHub, I decided to try Extension.js this time. It supports various frameworks like React and Vue, along with TypeScript—looks neat. You can scaffold a new project with the following command: Then, you are ready to start coding. It opens up another Chrome window with a development profile when running: When stopping the dev server, the Chrome window closes automatically. It even automatically reloads your extension whenever you make changes. Super convenient – I loved it. My extension includes a background script (called service worker in manifest v3), a popup window, and an options page. The looks like so: Since Firefox still doesn't support service worker scripts, you have to write the field like so: When compiling for Firefox, you can run the following command: I didn't want to spend so long building UI components, so I decided to try Radix UI Themes for the first time. It turned out it was great. Here is what my extension's UI looks like: It uses Dropdown Menu to implement these menus: As you can see it has an input bar for filtering items with keyword, which can be accomplished by adding TextField in the first menu like so: Adding and cancelling the default behavior for click events are important to prevent unexpected behaviors for the input field: Firefox requires you to provide source code if you are using a bundler like Webpack. So, I've added a script in my like so: It compresses files except for some redundant or private files. I hope these tips are helpful for your browser extension development!

0 views
Takuya Matsuyama 9 months ago

Supporting iOS Share Extensions & Android Intents on React Native

Hi, it's Takuya, the solo developer of Inkdrop , a note-taking app designed for software developers. Recently, I enabled a web clipper feature on the mobile app for both iOS and Android. I'd like to share how I implemented the logic to receive a shared URL in React Native. My mobile app is a 'bare' React Native project (not using Expo), because I started it more than seven years ago—well before Expo was a thing. If you use Expo, check out MaxAst/expo-share-extension . One challenge for React Native apps is how to display a custom view in an iOS share extension. Because a share extension and its containing app are separate processes, you can’t directly share instances or data, and you need a method of communication, such as storing files in the same App Group. Typically, apps send shared content to their servers, e.g., via REST APIs, and then load it in the containing app upon launch. However, because Inkdrop uses end-to-end encryption with its servers, supporting that same encryption flow in the share extension would be complicated. Instead, I decided to redirect to the containing app immediately after the user selects Inkdrop from the share sheet. This approach is used by other apps like Bluesky, which is also built with React Native. It appears that Apple permits launching a containing app from a share extension—there’s a Stack Overflow discussion about it. I also found a promising library called react-native-receive-sharing-intent , which provides a useful guide on setting up a share extension for iOS and handling shared Intents on Android. Instead of installing it, I followed the project setup steps from the documentation and wrote my own native code, because I prefer minimal dependencies and I’m comfortable tweaking native code. Here is a demo of Inkdrop: 0:00 / 0:04 1× In Xcode, go to File → New → Target... , then choose “Share Extension”. Give it a descriptive name (for example, "InkdropShare")—this name will appear in the share sheet. In my case, the app only accepts URLs, so the looks like this: After creating the extension, you should see its icon in the iOS share sheet. Xcode automatically creates a Swift file for the view controller ( ). This class is loaded by the share extension. To redirect to the containing app, I tested a snippet from the documentation, but it didn’t work. I ended up referring to Bluesky’s implementation and adapted the code: This code opens a deep link to the main app with the URI . React Native has built-in support for deep linking: For example: Android uses a concept called Intents to communicate between apps. If you have native Android experience, you’ll be familiar with it. Here, you’ll make your app capable of receiving shared URLs via Intents. Deep linking is not required to handle incoming Intents. Add an in your manifest to tell Android your app can accept text data from other apps: The library uses deep linking to detect incoming Intents, but this approach didn’t work in my project. The React Native module doesn’t emit a event for . Inside , you can see that it only handles or . You can manually detect in Kotlin (or Java) and pass the data to React Native. Here, lets you emit custom events to the JavaScript side. Once the event is dispatched, you can listen for it in your React code. Create a small module for listening to the custom event: Then, in your app: That’s the gist of how I added a share extension on iOS and handled on Android for my React Native app. I hope you find it helpful! Check out my app if you're looking for a Markdown note-taking app :) React Native Docs: Linking

0 views