Industry Context — Common BS Fingerprints in Blogs, Influencers & Personal Brands
overreacted (Dan Abramov)
(https://overreacted.io) 📸 Data Snapshot: May 25, 2026Analyze the raw signals below. How would a machine score this business’s credibility?
Here are the exact signals captured from up to six pages of the site — the same raw inputs the evaluation engine analyzed. They are grouped by signal type so you can weigh each the way the machine does.
🏗️ Semantic Structure — heading hierarchy & page identity (Info Density · Commodity Fingerprint)
HOMEPAGE overreacted — A blog by Dan Abramov (https://overreacted.io)
overreacted — A blog by Dan Abramov
A blog by Dan Abramov
HEADING_BODY A Social Filesystem — overreacted (https://overreacted.io/a-social-filesystem/)
A Social Filesystem — overreacted
Formats over apps.
HEADING_BODY Introducing RSC Explorer — overreacted (https://overreacted.io/introducing-rsc-explorer/)
Introducing RSC Explorer — overreacted
My new hobby project.
HEADING_BODY Hire Me in Japan — overreacted (https://overreacted.io/hire-me-in-japan/)
Hire Me in Japan — overreacted
I'm looking for a new job.
📝 The Narrative — clean text per page (Info Density · Semantic Coherence)
HOMEPAGE (https://overreacted.io) overreacted — A blog by Dan Abramov
[H2] A Social Filesystem January 18, 2026Formats over apps. [H2] Introducing RSC Explorer December 19, 2025My new hobby project. [H2] Hire Me in Japan November 11, 2025I'm looking for a new job. [H2] How to Fix Any Bug October 21, 2025The joys of vibecoding. [H2] Where It's at:// October 2, 2025From handles to hosting. [H2] Open Social September 26, 2025The protocol is the API. [H2] A Lean Syntax Primer September 2, 2025Programming with proofs. [H2] Beyond Booleans August 16, 2025What is the type of 2 + 2 = 4? [H2] The Math Is Haunted July 30, 2025A taste of Lean. [H2] Suppressions of Suppressions June 11, 2025I heard you like linting. [H2] I'm Doing a Little Consulting June 11, 2025Personal update post. [H2] How Imports Work in RSC June 5, 2025A layered module system. [H2] RSC for LISP Developers June 1, 2025Quoting for modules. [H2] Progressive JSON May 31, 2025Why streaming isn't enough. [H2] Why Does RSC Integrate with a Bundler? May 30, 2025One does not simply serialize a module. [H2] One Roundtrip Per Navigation May 29, 2025What do HTML, GraphQL, and RSC have in common? [H2] Static as a Server May 8, 2025You wouldn't download a site. [H2] RSC for Astro Developers May 6, 2025Islands, but make it fractal. [H2] Functional HTML May 2, 2025Tags on both sides. [H2] What Does "use client" Do? April 25, 2025Two worlds, two doors. [H2] Impossible Components April 22, 2025Composing across the stack. [H2] JSX Over The Wire April 16, 2025Turning your API inside-out. [H2] React for Two Computers April 9, 2025Two things, one origin. [H2] The Two Reacts January 4, 2024UI = f(data)(state) [H2] A Chain Reaction December 11, 2023The limits of my language mean the limits of my world. [H2] npm audit: Broken by Design July 7, 2021Found 99 vulnerabilities (84 moderately irrelevant, 15 highly irrelevant) [H2] Before You memo() February 23, 2021Rendering optimizations that come naturally. [H2] The WET Codebase July 13, 2020Come waste your time with me. [H2] Goodbye, Clean Code January 11, 2020Let clean code guide you. Then let it go. [H2] My Decade in Review January 1, 2020A personal reflection. [H2] What Are the React Team Principles? December 25, 2019UI Before API. [H2] On let vs const December 22, 2019So which one should I use? [H2] What Is JavaScript Made Of? December 20, 2019Getting a closure on JavaScript. [H2] How Does the Development Mode Work? August 4, 2019Dead code elimination by convention. [H2] Algebraic Effects for the Rest of Us July 21, 2019They’re not burritos. [H2] Preparing for a Tech Talk, Part 3: Content July 10, 2019Turning an idea into a talk. [H2] Name It, and They Will Come March 25, 2019A change starts with a story. [H2] Writing Resilient Components March 16, 2019Four principles to set you on the right path. [H2] A Complete Guide to useEffect March 9, 2019Effects are a part of your data flow. [H2] How Are Function Components Different from Classes? March 3, 2019They’re a whole different Pokémon. [H2] Coping with Feedback March 2, 2019Sometimes I can’t fall asleep. [H2] Fix Like No One’s Watching February 15, 2019The other kind of technical debt. [H2] Making setInterval Declarative with React Hooks February 4, 2019How I learned to stop worrying and love refs. [H2] React as a UI Runtime February 2, 2019An in-depth description of the React programming model. [H2] Why Isn’t X a Hook? January 26, 2019Just because we can, doesn’t mean we should. [H2] The “Bug-O” Notation January 25, 2019What is the ?(n) of your API? [H2] Preparing for a Tech Talk, Part 2: What, Why, and How January 7, 2019We need to go deeper. [H2] The Elements of UI Engineering December 30, 2018What makes UI engineering difficult? [H2] Things I Don’t Know as of 2018 December 28, 2018We can admit our knowledge gaps without devaluing our expertise. [H2] Preparing for a Tech Talk, Part 1: Motivation December 26, 2018Here’s my recipe for a good talk idea. [H2] Why Do React Hooks Rely on Call Order? December 13, 2018Lessons learned from mixins, render props, HOCs, and classes. [H2] Optimized for Change December 12, 2018What makes a great API? [H2] How Does setState Know What to Do? December 9, 2018Dependency injection is nice if you don’t have to think about it. [H2] My Wishlist for Hot Reloading December 8, 2018I don't want a lot for Christmas. There is just one thing I need. [H2] Why Do React Elements Have a $$typeof Property? December 3, 2018It has something to do with security. [H2] How Does React Tell a Class from a Function? December 2, 2018We talk about classes, new, instanceof, prototype chains, and API design. [H2] Why Do We Write super(props)? November 30, 2018There’s a twist at the end.
SUB-PAGE (https://overreacted.io/a-social-filesystem/) A Social Filesystem — overreacted
[H1] A Social Filesystem
January 18, 2026Pay what you likeRemember files?
You write a document, hit save, and the file is on your computer. It’s yours. You can inspect it, you can send it to a friend, and you can open it with other apps.
Files come from the paradigm of personal computing.
This post, however, isn’t about personal computing. What I want to talk about is social computing—apps like Instagram, Reddit, Tumblr, GitHub, and TikTok.
What do files have to do with social computing?
Historically, not a lot—until recently.
But first, a shoutout to files.
[H2] #Why Files Are Awesome
Files, as originally invented, were not meant to live inside the apps.
Since files represent your creations, they should live somewhere that you control. Apps create and read your files on your behalf, but files don’t belong to the apps.
Files belong to you—the person using those apps.
Apps (and their developers) may not own your files, but they do need to be able to read and write them. To do that reliably, apps need your files to be structured. This is why app developers, as part of creating apps, may invent and evolve file formats.
A file format is like a language. An app might “speak” several formats. A single format can be understood by many apps. Apps and formats are many-to-many. File formats let different apps work together without knowing about each other.
Consider this .svg:
SVG is an open specification. This means that different developers agree on how to read and write SVG. I created this SVG file in Excalidraw, but I could have used Adobe Illustrator or Inkscape instead. Your browser already knew how to display this SVG. It didn’t need to hit any Excalidraw APIs or to ask permissions from Excalidraw to display this SVG. It doesn’t matter which app has created this SVG.
The file format is the API.
Of course, not all file formats are open or documented.
Some file formats are application-specific or even proprietary like .doc. And yet, although .doc was undocumented, it didn’t stop motivated developers from reverse-engineering it and creating more software that reads and writes .doc:
Another win for the files paradigm.
The files paradigm captures a real-world intuition about tools: what we make with a tool does not belong to the tool. A manuscript doesn’t stay inside the typewriter, a photo doesn’t stay inside the camera, and a song doesn’t stay in the microphone.
Our memories, our thoughts, our designs should outlive the software we used to create them. An app-agnostic storage (the filesystem) enforces this separation.
A file has many lives.
You may create a file in one app, but someone else can read it using another app. You may switch the apps you use, or use them together. You may convert a file from one format to another. As long as two apps correctly “speak” the same file format, they can work in tandem even if their developers hate each others’ guts.
And if the app sucks?
Someone could always create “the next app” for the files you already have:
Apps may come and go, but files stay—at least, as long as our apps think in files.
[H2] #The Everything Folder
When you think of social apps—Instagram, Reddit, Tumblr, GitHub, TikTok—you probably don’t think about files. Files are for personal computing only, right?
A Tumblr post isn’t a file.
An Instagram follow isn’t a file.
A Hacker News upvote isn’t a file.
But what if they behaved as files—at least, in all the important ways? Suppose you had a folder that contained all of the things ever POSTed by your online persona:
It would include everything you’ve created across different social apps—your posts, likes, scrobbles, recipes, etc. Maybe we can call it your “everything folder”.
Of course, closed apps like Instagram aren’t built this way. But imagine they were. In that world, a “Tumblr post” or an “Instagram follow” are social file formats:
You posting on Tumblr would create a “Tumblr post” file in your folder.
You following on Instagram would put an “Instagram follow” file into your folder.
You upvoting on Hacker News would add an “HN upvote” file to your folder.
Note this folder is not some kind of an archive. It’s where your data actually lives:
Files are the source of truth—the apps would reflect whatever’s in your folder.
Any writes to your folder would be synced to the interested apps. For example, deleting an “Instagram follow” file would work just as well as unfollowing through the app. Crossposting to three Tumblr communities could be done by creating three “Tumblr post” files. Under the hood, each app manages files in your folder.
In this paradigm, apps are reactive to files. Every app’s database mostly becomes derived data—an app-specific cached materialized view of everybody’s folders.
[H2] #A Social Filesystem
This might sound very hypothetical, but it’s not. What I’ve described so far is the premise behind the AT protocol. It works in production at scale. Bluesky, Leaflet, Tangled, Semble, and Wisp are some of the new open social apps built this way.
It doesn’t feel different to use those apps. But by lifting user data out of the apps, we force the same separation as we’ve had in personal computing: apps don’t trap what you make with them. Someone can always make a new app for old data:
Like before, app developers evolve their file formats. However, they can’t gatekeep who reads and writes files in those formats. Which apps to use is up to you.
Together, everyone’s folders form something like a distributed social filesystem:
I’ve previously written about the AT protocol in Open Social, looking at its model from a web-centric perspective. But I think that looking at it from the filesystem perspective is just as intriguing, so I invite you to take a tour of how it works.
A personal filesystem starts with a file.
What does a social filesystem start with?
[H3] #A Record
Here is a typical social media post:
How would you represent it as a file?
It’s natural to consider JSON as a format. After all, that’s what you’d return if you were building an API. So let’s fully describe this post as a piece of JSON:
{
author: {
avatar: 'https://example.com/dril.jpg',
displayName: 'wint',
handle: 'dril'
},
text: 'no',
createdAt: '2008-09-15T17:25:00.000Z',
replyCount: 819,
repostCount: 56137,
likeCount: 125381
}
However, if we want to store this post as a file, it doesn’t make sense to embed the author information there. After all, if the author later changes their display name or avatar, we wouldn’t want to go through their every post and change them there.
So let’s assume their avatar and name live somewhere else—perhaps, in another file. We could leave author: 'dril' in the JSON but this is unnecessary too. Since this file lives inside the creator’s folder—it’s their post, after all—we can always figure out the author based on whose folder we’re currently looking at.
Let’s remove the author field completely:
{
text: 'no',
createdAt: '2008-09-15T17:25:00.000Z',
replyCount: 819,
repostCount: 56137,
likeCount: 125381
}
This seems like a good way to describe this post:
But wait, no, this is still wrong.
You see, replyCount, repostCount, and likeCount are not really something that the post’s author has created. These values are derived from the data created by other people—their replies, their reposts, their likes. The app that displays this post will have to keep track of those somehow, but they aren’t this user’s data.
So really, we’re left with just this:
{
text: 'no',
createdAt: '2008-09-15T17:25:00.000Z'
}
That’s our post as a file!
Notice how it took some trimming to identify which parts of the data actually belong in this file. This is something that you have to be intentional about when creating apps with the AT protocol. My mental model for this is to think about the POST request. When the user created this thing, what data did they send? That’s likely close to what we’ll want to store. That’s the stuff the user has just created.
Our social filesystem will be structured more rigidly than a traditional filesystem. For example, it will only consist of JSON files. To make this more explicit, we’ll start introducing our new terminology. We’ll call this kind of file a record.
[H3] #Record Keys
Now we need to give our record a name. There are no natural names for posts. Could we use sequential numbers? Our names need only be unique within a folder:
posts/
├── 1.json
├── 2.json
└── 3.json
One downside is that we’d have to keep track of the latest one so there’s a risk of collisions when creating many files from different devices at the same time.
Instead, let’s use timestamps with some per-clock randomness mixed in:
posts/
├── 1221499500000000-c5.json
├── 1221499500000000-k3.json # clock id helps avoid global collisions
└── 1221499500000001-k3.json # artificial +1 avoids local collisions
This is nicer because these can be generated locally and will almost never collide.
We’ll use these names in URLs so let’s encode them more compactly. We’ll pick our encoding carefully so that sorting alphabetically goes in the chronological order:
posts/
├── 34qye3wows2c5.json
├── 34qye3wows2k3.json
└── 34qye3wows3k3.json
Now ls -r gives us a reverse chronological timeline of posts! That’s neat. Also, since we’re sticking with JSON as our lingua franca, we don’t need file extensions.
posts/
├── 34qye3wows2c5
├── 34qye3wows2k3
└── 34qye3wows3k3
Not all records accumulate over time. For example, you can write many posts, but you only have one copy of profile information—your avatar and display name. For “singleton” records, it makes sense to use a predefined name, like me or self:
posts/
├── 34qye3wows2c5
├── 34qye3wows2k3
└── 34qye3wows3k3
profiles/
└── self
By the way, let’s save this profile record to profiles/self:
{
avatar: 'https://example.com/dril.jpg",
displayName: 'wint'
}
Note how, taken together, posts/34qye3wows2c5 and profiles/self let us reconstruct more of the UI we started with, although some parts are still missing:
Before we fill them in, though, we need to make our system sturdier.
[H3] #Lexicons
This was the shape of our post record:
{
text: 'no',
createdAt: '2008-09-15T17:25:00.000Z'
}
And this was the shape of our profile record:
{
avatar: 'https://example.com/dril.jpg",
displayName: 'wint'
}
Since these are stored as files, it’s important for the format not to drift.
Let’s write some type definitions:
type Post = {
text: string,
createdAt: string
};
type Profile = {
avatar?: string,
displayName?: string
};
TypeScript seems convenient for this but it isn’t sufficient. For example, we can’t express constraints like “the text string should have at most 300 Unicode graphemes”, or “the createdAt string should be formatted as datetime”.
We need a richer way to define social file formats.
We might shop around for existing options (RDF? JSON Schema?) but if nothing quite fits, we might as well design our own schema language explicitly geared towards the needs of our social filesystem. This is what our Post looks like:
{
// ...
"defs": {
"main": {
"type": "record",
"key": "tid",
"record": {
"type": "object",
"required": ["text", "createdAt"],
"properties": {
"text": { "type": "string", "maxGraphemes": 300 },
"createdAt": { "type": "string", "format": "datetime" }
}
}
}
}
}
We’ll call this the Post lexicon because it’s like a language our app wants to speak.
My first reaction was also “ouch” but it helped to think that conceptually it’s this:
type Post = {
@maxGraphemes(300) text: string,
createdAt: datetime
};
I used to yearn for a better syntax but I’ve actually come around to hesitantly appreciate the JSON. It being trivial to parse makes it super easy to build tooling around it (more on that in the end). And of course, we can make bindings turning these into type definitions and validation code for any programming language.
[H3] #Collections
Our social filesystem looks like this so far:
posts/
├── 34qye3wows2c5
├── 34qye3wows2k3
└── 34qye3wows3k3
profiles/
└── self
The posts/ folder has records that satisfy the Post lexicon, and the profiles/ folder contains records (a single record, really) that satisfy the Profile lexicon.
This can be made to work well for a single app. But here’s a problem. What if there’s another app with its own notion of “posts” and “profiles”?
Recall, each user has an “everything folder” with data from every app:
Different apps will likely disagree on what the format of a “post” is! For example, a microblog post might have a 300 character limit, but a proper blog post might not.
Can we get the apps to agree with each other?
We could try to put every app developer in the same room until they all agree on a perfect lexicon for a post. That would be an interesting use of everyone’s time.
For some use cases, like cross-site syndication, a standard-ish jointly governed lexicon makes sense. For other cases, you really want the app to be in charge. It’s actually good that different products can disagree about what a post is! Different products, different vibes. We’d want to support that, not to fight it.
Really, we’ve been asking the wrong question. We don’t need every app developer to agree on what a post is; we just need to let anyone “define” their own post.
We could try namespacing types of records by the app name:
twitter/
├── posts/
│ ├── 34qye3wows2c5
│ ├── 34qye3wows2k3
│ └── 34qye3wows3k3
└── profiles/
└── self
tumblr/
├── posts/
│ ├── 34qye3wows4c5
│ └── 34qye3wows5k3
└── profiles/
└── self
But then, app names can also clash. Luckily, we already have a way to avoid conflicts—domain names. A domain name is unique and implies ownership.
Why don’t we take some inspiration from Java?
com.twitter.post/
├── 34qye3wows2c5
├── 34qye3wows2k3
└── 34qye3wows3k3
com.twitter.profile/
└── self
com.tumblr.post/
├── 34qye3wows4c5
└── 34qye3wows5k3
com.tumblr.profile/
└── self
This gives us collections.
A collection is a folder with records of a certain lexicon type. Twitter’s lexicon for posts might differ from Tumblr’s, and that’s fine—they’re in separate collections. The collection is always named like <whoever.designs.the.lexicon>.<name>.
For example, you could imagine these collection names:
com.instagram.follow for Instagram follows
fm.last.scrobble for Last.fm scrobbles
io.letterboxd.review for Letterboxd reviews
You could also imagine these slightly whackier collection names:
com.ycombinator.news.vote (subdomains are ok)
co.wint.shitpost (personal domains work too)
org.schema.recipe (a shared standard someday?)
fm.last.scrobble_v2 (breaking changes = new lexicon, just like file formats)
It’s like having a dedicated folder for every file extension.
To see some real lexicon names, check out UFOs and Lexicon Garden.
[H3] #There Is No Lexicon Police
If you’re an application author, you might be thinking:
Who enforces that the records match their lexicons? If any app can (with the user’s explicit consent) write into any other app’s collection, how do we not end up with a lot of invalid data? What if some
SUB-PAGE (https://overreacted.io/introducing-rsc-explorer/) Introducing RSC Explorer — overreacted
[H1] Introducing RSC Explorer
December 19, 2025Pay what you likeIn the past few weeks, since the disclosure of the critical security vulnerability in React Server Components (RSC), there’s been a lot of interest in the RSC protocol.
The RSC protocol is the format in which React trees (and a superset of JSON) get serialized and deserialized by React. React provides both a writer and a reader for the RSC protocol, which are versioned and evolved in lockstep with each other.
Because the RSC protocol is an implementation detail of React, it is not explicitly documented outside the source code. The benefit of this approach is that React has a lot of leeway to improve the format and add new features and optimizations to it.
However, the downside is that even people who actively build apps with React Server Components often don’t have an intuition for how it works under the hood.
A few months ago, I wrote Progressive JSON to explain some of the ideas used by the RSC protocol. While you don’t “need” to know them to use RSC, I think it’s one of the cases where looking under the hood is actually quite fun and instructive.
I wish the circumstances around the increased interest now were different, but in any case, that interest inspired me to make a new little tool to show how it works.
I’m calling it RSC Explorer, and you can find it at https://rscexplorer.dev/.
Obviously, it’s open source.
“Show, don’t tell”, as they say. Well, there it is as an embed.
Let’s start with the Hello World:
Notice there’s a yellow highlighted line that says something cryptic. If you look closely, it’s <h1>Hello</h1> represented as a piece of JSON. This line is a part of the RSC stream from the server. That’s how React talks to itself over the network.
Now press the big yellow “step” button!
Notice how <h1>Hello</h1> now appears on the right. This is the JSX that the client reconstructs after reading this line. We’ve just seen a simple piece of JSX—the <h1>Hello</h1> tag—cross the network and get revived on the other side.
Well, not really “cross the network”.
One cool thing about RSC Explorer is that it’s a single-page app, i.e. it runs entirely in your browser (more precisely, the Server part runs in a worker). This is why, if you check the Network tab, you’ll see no requests. So in a sense it’s a simulation.
Nevertheless, RSC Explorer is built using exactly the same packages that React provides to read and write the RSC protocol, so every line of the output is real.
[H2] #Async Component
Let’s try something slightly more interesting to see streaming in action.
Take this example and press the big yellow “step” button exactly two times:
(If you miscounted, press “restart” on the left, and then “step” two times again.)
Have a look at the upper right pane. You can see three chunks in the RSC protocol format (which, again, you don’t technically need to read—and which changes between versions). On the right, you see what Client React reconstructed so far.
Notice a “hole” in the middle of the streamed tree, visualized as a “Pending” pill.
By default, React would not show an inconsistent UI with “holes”. However, since you’ve declared a loading state with <Suspense>, a partially completed UI now can be displayed (notice how the <h1> is already visible but <Suspense> shows the fallback content because <SlowComponent /> has not streamed in yet).
Press the “step” button once again, and the “hole” will be filled.
[H2] #Counter
So far, we’ve only sent data to the client; now let’s also send some code.
Let’s use a counter as the classic example.
Press the big yellow “step” button twice:
That’s just a good old counter, nothing too interesting here.
Or is there?
Have a look at the protocol payload. It’s a bit tricky to read, but notice that we’re not sending the string "Count: 0" or the <button>s, or any HTML. We’re sending <Counter initialCount={0} /> itself—the “virtual DOM”. It can, of course, be turned to HTML later, just like any JSX can, but it doesn’t have to be.
It’s like we’re returning React trees from API routes.
Notice how the Counter reference becomes ["client",[],"Counter"] in the RSC protocol, which says “grab the Counter export from the client module”. In a real framework, this would be done by the bundler, which is why RSC integrates with bundlers. If you’re familiar with webpack, this is similar to reading from the webpack require cache. (In fact, that’s how RSC Explorer implements that.)
[H2] #Form Action
We’ve just seen the server referring to a piece of code exposed by the client.
Now let’s see the client referring to a piece of code exposed by the server.
Here, greet is a Server Action, exposed with 'use server' as an endpoint. It’s passed as a prop to the Client Form component that sees it as an
SUB-PAGE (https://overreacted.io/hire-me-in-japan/) Hire Me in Japan — overreacted
[H1] Hire Me in Japan November 11, 2025My sabbatical is soon coming to an end, and I am looking for a new job. In particular, I am looking for a job at a company that would like to sponsor a working visa for me in Japan, where I’d like to relocate within the next year. If you can sponsor a software engineering visa in Japan and think I might be a good fit, please email [email protected]. Below I’ll recap some of my past work, with more details re: what I’m looking for near the end of this page. (Skip to the end) [H3] #Past Work Hi! My name is Dan Abramov. I started programming about 20 years ago and then I couldn’t stop—so I’ve been doing software for over 15 years professionally. I’ve dabbled in different languages, but the vast majority of my recent work has been in JavaScript and TypeScript. Here’s a few things I have worked on over the years. [H4] #2025: Consulting This year, I’ve been doing consulting, so there isn’t much I can say publicly. Mostly, I’ve been consulting teams using React on how to approach engineering challenges related to performance and state management in complex apps. On the side, I’ve been contributing to Terence Tao’s Analysis textbook in Lean. [H4] #2023–2025: The Bluesky app From 2023 to 2025, I worked on the official Bluesky client app (in React Native). Most of my engineering work focused on improving the app quality, for example: Implementing animations for the lightbox Synchronizing feed swipe animations with gestures Introducing custom lint rules to prevent runtime crashes Shaving off seconds from Android start time Some of this work required multi-week deep dives and sprawling refactors. Rewriting the lightbox to work well on Android Reworking the cross-platform layout to work well on the web Revamping how threads show up in the feed Revamping the post composer into a thread composer The Bluesky app is open source; here’s a link to my other merged pull requests. We’ve used a lot of open source software at Bluesky, and sometimes it could be difficult to trace down where a bug is coming from. Occasionally, I’ve had to do deep dive investigations into the underlying projects to file bugs or fixes there. Reducing the Reanimated serialization traffic Fixing a 10 year old ScrollView bug in React Native Documenting the difficulties in getting gestures to work with ScrollView In addition to my individual engineering work, I’ve done some engineering management and mentoring on the application team. This included: Helping the team get a natural mental model for working with React. Mentoring the application team on how to root cause particularly gnarly issues. Pushing for a closer collaboration with the backend team so that the seams from the client/server organizational split don’t “show up” as poor UX in the product. I’ve also helped the team explain the AT protocol to a broader community—first in a talk last year, which then crystallized into my recent article called Open Social. [H4] #2015–2023: React at Meta/Facebook Before Bluesky, I used to work on the React team at Meta (formerly Facebook). Some of the more visible projects I was involved with include: The React Documentation, which I co-wrote with Rachel Lee Nabors and others. My work on it included designing the Learn section curriculum, iterating on the Reference page structure, a decent chunk of technical work on the website itself, and much of the actual writing, including the design of examples and challenges. The public messaging and rollout of React Hooks, including the original documentation for React Hooks and the conference talk introducing them. Implementing Fast Refresh (hot reloading / live editing) as a first-class React feature. It feels like a distant past, but we used to press Cmd+R to see our edits. Co-creating Create React App, which ended the “JavaScript fatigue” (allegedly). I’ve also done some other technical work on React over the years, which mostly consisted of fixing bugs and occasionally revamping the build infrastructure. Outside of my job, I co-created Just JavaScript, which is a half-book half-course introduction to thinking in JavaScript, aiming to be both whimsical and rigorous. [H4] #Before 2015 I haven’t done many publicly notable things before getting hired at Facebook, other than accidentally co-creating Redux as a demo for my conference talk. I’ve previously worked at a small product company that didn’t succeed doing some JavaScript and C#, and before that at an outsourcing firm where I mostly did C#. I also created React Hot Loader (a very early precursor to Fast Refresh, now built into React), React DnD, and normalizr (which was used by Twitter for some time). [H3] #Looking Forward As you can tell from the above, most of my engineering expertise lies in the field of UI engineering, web development in particular, and of course in using React. I’d love an opportunity to share my expertise and to help you create better apps. I enjoy sharing what I learned, which is why I blog and do talks. Although I prefer when I can work on open source software, this will not be a requirement for me. Currently I feel most comfortable with JavaScript/TypeScript. I’ve recently picked up some Lean, and working with it professionally seems alluring (if unlikely). I’ve been using LLMs quite a bit recently too and am open to working with them more. In general, I’m open to learning new things on the job (for example, I’ve learned React Native while at Bluesky!) but a new stack may require some ramp-up time. I care about the quality of what I’m working on, whether it’s an app, a developer tool, or a course. I hope to find a job where caring about quality is appreciated. I know fixing things “the right way” isn’t always possible, but I feel most useful when I’m able to dig into the root causes, and work with others on solving them. To sum up, I’m looking for a software engineering job… in Japan. [H3] #Why Japan Why indeed! The honest answer is that the feeling of home has moved, and so now I must try to move along with it. I don’t know how it happened exactly. My wife and I first visited Japan a year ago, staying for a few months in Kyoto. After coming home to London, we realized that something was off, so this spring we came back to Kyoto for a few more months. And now we’re back in Kyoto for a few more months again. (Big thanks to the Vue Fes Japan 2025 organizers for covering our recent flights!) Paying rent in both cities is expensive, flights are disruptive, and we want to adopt a cat, so we have to choose. We’ve loved spending a whole decade in London, but this decade, Kyoto feels right. The question isn’t whether to move but—can it be? I haven’t learned Japanese yet, which significantly limits my options. I’ve learned hiragana and katakana during the last trip, so now I’m focused on N5 grammar and vocab. I pick up my speed a bit slowly so I expect Japanese to take me a while. Since I don’t speak Japanese yet and I’m hoping to relocate to Kyoto, I suspect that the most promising option to obtain a work visa will either be an international company with a Japanese presence, or a Japanese company that permits remote work (I assume there aren’t many tech opportunities in Kyoto itself!) and that does most of the work-related communication in English. (I do hope to get to a fluent level of Japanese eventually, but that will likely take me at least a few more years.) I know there aren’t many options like this, but fingers crossed. I’m talking to a few companies but I would like to get a better sense of the options—hence this post. My hope is to find a real job that lets me come back with a working visa (rather than as a tourist, like now) and to settle down in Japan for the foreseeable future. If you would like to explore working with me and can sponsor my work visa in Japan, please reach out via [email protected] and let me know! And if you know someone who might, any leads and intros are very appreciated. Thank you. DanFork on Tangled
🛡️ Trust Signals — reviews, proof links, trust-theatre flag (Trust & Proof)
| Page | Reviews | Proof links |
|---|---|---|
| / (home) | 5 | 0 |
| /a-social-filesystem/ | 4 | 0 |
| /introducing-rsc-explorer/ | 2 | 0 |
| /hire-me-in-japan/ | 2 | 0 |
🔗 Identity & Technical Layer — schema JSON-LD: identity chains, entity gaps (Identity & Authority)
Your Diagnosis
Before revealing the machine’s verdict, predict the BS score for each signal. Higher = more BS (more fluff, less verifiable substance). Drag each slider, then submit to compare your judgment against the engine.
Stuck? Reveal the heuristic lens — how the deterministic page-auditor reads each signal (no AI, pure pattern rules)
These are the structural rules a local, deterministic auditor applies — the same lens you can use to judge each signal. They describe what to look for, not this company’s result.
Classify each sentence as substantive or hollow. Grounding markers — numbers, currencies, dates, technical units, named entities — outweigh marketing adjectives. When fluff sits right next to hard evidence, the fluff is forgiven.
Pull the main entities out of the H1, then check whether they actually recur through the body. A page that announces one thing and then talks about another drifts. Headings with no real sentences underneath read as pseudo-substance.
Count trust words (review, testimonial, rating, verified) against real outbound proof links (Google, Trustpilot, Clutch, G2, Yelp). Lots of trust language with zero verification links is trust theatre. Unlinked logo galleries count against it.
Look at how much sentence length varies. Natural writing varies its rhythm; templated or mass-produced copy is statistically uniform. Very low variation reads as commodity content — unless unique named entities break the pattern.
Inspect the JSON-LD. Is there an Organization or Person schema, and does it carry sameAs links to real external profiles (LinkedIn, socials)? Missing schema or no identity declaration signals an anonymous entity.
Want to apply this lens yourself? The free BS Indicator Chrome extension runs these heuristic checks live on any page. Bear in mind it is a single-page, deterministic tool — it relies only on pattern rules for the page in front of it and does not perform the cross-page semantic correlation this audit uses, so its readout is a starting lens, not the full verdict.
Based on 218 businesses audited.
Blogs, Influencers & Personal Brands BS: overreacted (Dan Abramov) (overreacted.io)
This is a rare specimen of a zero-bullshit personal brand. It avoids all industry tropes, focusing instead on extreme technical specificity and verifiable professional history. It is a benchmark for what substance looks like in the tech influencer space.
Add JSON-LD Person and BlogPosting schema to formalize the high level of authority for search crawlers. Include a ‘sameAs’ array in schema to link to established profiles like GitHub and Twitter to close the identity gap. Maintain the current ‘minimalist-first’ content strategy as it is the core of the brand’s high credibility.
The site is a textbook example of a high-authority personal brand within the software engineering niche. The content focuses exclusively on deep technical education and career updates, perfectly matching the Influencer/Personal Brand category but with an atypically high substance-to-signal ratio.
“The score of 5 is driven almost entirely by minor technical gaps, such as the absence of structured data (schema_json) and basic meta-descriptions. In terms of content and trust, the site is effectively flawless, representing the lowest possible BS levels for a personal brand.”
This training module utilizes a snapshot of public data from overreacted (Dan Abramov), captured on May 25, 2026, to demonstrate how machine logic evaluates different types of business narratives.
Purpose: This data is presented under “Fair Use” / “Educational Exception” for the purpose of forensic semantic analysis, allowing users to compare human intuition against machine-generated evaluations.
Notice to overreacted (Dan Abramov): This analysis is part of a non-adversarial audit conducted by 1 Euro SEO. The results provided by 1EuroSEO are intended as professional feedback to help improve any website’s machine-readability and authority signals. The 1EuroSEO BS Detection Tool is a free tool, and anyone can test any company to see how their content is interpreted by AI models.
Any company can use the insights for free and improve its voice by comparing it to industry clichés or competitors. When a company has updated its content, it can always submit a new audit request, which will be reflected in a new current score.
To all users: You are encouraged to visit the live site at https://overreacted.io to view the most current version of its content and learn from the source what this company is about and what it offers.