RADAR LIVE: 116 USEFUL DISCOVERIES • ⚡ SHORT DEMO WALKTHROUGHS PUBLISHED DAILY • ✳ APPS, AI TOOLS & OPEN-SOURCE FINDS • 🔄 SANE ALTERNATIVES TO EXPENSIVE SUBSCRIPTIONS • FOLLOW @THESTACKRADAR ON YOUTUBE & INSTAGRAM • RADAR LIVE: 116 USEFUL DISCOVERIES • ⚡ SHORT DEMO WALKTHROUGHS PUBLISHED DAILY • ✳ APPS, AI TOOLS & OPEN-SOURCE FINDS • 🔄 SANE ALTERNATIVES TO EXPENSIVE SUBSCRIPTIONS • FOLLOW @THESTACKRADAR ON YOUTUBE & INSTAGRAM

cybersemics/em

em

A beautiful, minimalistic note-taking app for personal sensemaking.

RECORDED STARS358
RECORDED FORKS141

THE USEFUL PART

What em does.

A beautiful, minimalistic note-taking app for personal sensemaking.

knowledge-managementnote-takingoutlinersensemakingtools-for-thought
Language
TypeScript
Source license
NOASSERTION
Project website
GitHub repository
Repository updated
2026-11-12
Content checked
2026-11-12

THE STACKRADAR WALKTHROUGH

Three useful things to know.

A short introduction from our reel. See the project README for the current details.

01

Focus without distraction Nonlinear note linking

This repo lets you capture ideas in a minimal interface that supports focus, nonlinearity, and associative links, so your notes stay organized and easy to explore.

02

Flow with every thought Organic thinking enabled

This repo also structures your workflow, letting you move between notes fluidly and build organic connections, which keeps your creative process uninterrupted and natural.

03

Build a concept web Contextual knowledge map

Finally, the app creates a semiotic web that mediates concepts, giving you a contextual map of ideas that deepens understanding and reveals hidden relationships.

GITHUB SNAPSHOT

The project in numbers.

Recorded counts, not a growth rate or a quality score.

OBSERVED STAR HISTORY

Follow the signal over time.

Tracking starts here.

Daily source snapshots are collected automatically. A trend appears after at least two real observations—no invented historical growth.

Repository screenshot / emOpen source page
em repository screenshot

FROM THE PROJECT

README & features

Source excerpts from the project's README. Not an independent review, verification or security audit.

em

em is a beautiful, minimalistic note-taking app for personal sensemaking.

cognitively-informed - Supports focus, nonlinearity, and associative connectivity.

process-oriented - Facilitates flow and organic thinking.

semiotic - Mediates concept through a monistic, contextual semiotic web.

Documentation

Overview - An overview of the architecture, data structures, and tips for contributors.

Roadmap - A high-level overview of the project, including vision and objectives.

Setup

Install dependencies:

yarn

Start the dev server for local development:

yarn start

Testing

There are two testing scripts:

yarn test - Unit tests covering Redux actions, reducers, util, components with react-testing-library on JSDOM.

yarn test:puppeteer - Puppeteer tests will test realistic user behavior against a headless Chrome instance. Requires Docker for platform-independent execution.

Windows

You will need the Bash CLI on your system to run the Puppeteer tests on Windows.

There are two ways to run bash on Windows:

Windows Subsystem for Linux (WSL)

Install Ubuntu in your Windows Linux Subsystem. (Search on google for installation guide.)

Run Ubuntu and you will have bash available by default.

yarn and yarn start as above.

Git Bash

Install git with bash cli in windows.

Open the code repository in bash cli.

yarn and yarn start as above.

Native App Development

em is a Progressive Web App (PWA) that runs on native platforms using Capacitor.

Prerequisites

For iOS development, ensure Xcode and CocoaPods are installed.

For Android development, ensure Android Studio is installed.

Modes

There are two development modes that determine where the Capacitor build loads the web resources from. Each mode can be run on iOS or Android.

ModeDescriptioniOSAndroid
liveConnect to live dev server at CAPACITOR_SERVER_URLyarn cap:iosyarn cap:android
staticBuild production app and output to /buildyarn cap:ios:staticyarn cap:android:static

Live (default)

Runs off the local Vite development server. Ideal for rapid prototyping, debugging, and hot-reloading your changes.

Set the development server URL

Update your local development environment file (.env.development.local) by setting the following variable to the URL of your Vite dev server.

   CAPACITOR_SERVER_URL=https://192.168.x.x:3000

Note: Use your machine's local network IP (e.g., https://192.168.x.x:3000) rather than localhost (https://localhost:3000).

Start the Vite development server

   yarn start

Synchronise the native project and open it in the IDE

   yarn cap:ios       # runs cap:sync and opens iOS project in Xcode
   yarn cap:android   # runs cap:sync and opens Android project in Android Studio

Notes:

Make sure to run these commands again any time you change CAPACITOR_SERVER_URL.

If you see a blank screen when the app starts, then either CAPACITOR_SERVER_URL is wrong or you need to disable your VPN/firewall.

Static

Outputs the production build to /build and syncs capacitor to the static build output. This will test the production build output, but allow inspecting the WebView and attaching a debugger.

yarn cap:ios:static     # runs cap:sync pointing to static /build output
yarn cap:android:static # runs cap:sync pointing to static /build output

Other Scripts

cap:copy – Copies the web app build and Capacitor configuration file into the native platform project. Run this each time you make changes that are not picked up by the live-reload server, and when you change a configuration value in capacitor.config.ts.

cap:sync – Runs cap:copy and updates native Capacitor plugins.

cap:copy:prod – Copies the Capacitor configuration in "release" mode. WebView is not inspectable and debugger cannot be attached.

cap:sync:prod – Syncs in "release" mode.

Deployment

em is an offline-first app that can run on a static web server.

Environment variables are set in the appropriate .env file: .env.development and .env.production. Only .env.production is kept in source control. Environment variables that are prepended with VITE will be bundled with the build and available client-side.

# Build the static HTML/CSS/JS app in the /build directory
yarn build

# Run the static build with npx serve -s build -l 3000
yarn servebuild

Deploy with Vercel:

npm install -g vercel

yarn deploy:dev

Component Hierarchy

To the user, a thought just consists of a bullet, text, and superscript indicating the number of contexts the thought appears in. The component hierarchy, however, consists of several components that control positioning (LayoutTree), window virtualization (VirtualThought), and superscript positioning (ThoughtAnnotation). The deep hierarchy ensures that if a thought is hidden, complex selectors and other computations are short-circuited.

└─Content
  └─LayoutTree
    └─VirtualThought
      └─Subthought
        └─Thought
          ├─Bullet
          └─StaticThought
            ├─ThoughtAnnotationContainer
            │ └─ThoughtAnnotation
            │   └─StaticSuperscript
            └─Editable

- Root container that defines the margins of the thoughtspace and handles clicking on empty space.

- Renders all visible thoughts as absolutely positioned siblings to allow for conditional rendering of ancestors, list virtualization, and animation across levels.

- Conditionally renders a shim when the thought is hidden by autofocus. The shim is a simple div with a height attribute matching the thought's height.

- Renders the Bullet and the Thought.

- This is, unsurprisingly, the bullet of the thought.

- Contains the Editable and ThoughtAnnotation.

- Conditionally renders the ThoughtAnnotation only when needed.

- A non-interactive, hidden clone of the Thought that is used to position the Superscript at the end of the Thought. This is needed because the Thought has an extended click area, while the Superscript needs to be rendered flush to the right edge of the text.

- Renders the number of contexts a thought appears in as a superscript.

- Renders the thought text as a content-editable and handles live editing, throttled updates, selection, pasting, and all other editing capacities.

Styles

This project uses PandaCSS for styling. Styles are automatically generated from ts files at compile-time when the dev server is running.

Prefer inline styles, e.g. css({ margin: '10px', padding: '10px' })

Define recipes for complex shared styles.

If the styles get out of sync, restart the dev server or run panda codegen.

See: https://panda-css.com/docs/concepts/writing-styles

Custom Dependencies

Every dependency resolves to the npm registry, which yarn lint:lockfile enforces, so yarn install needs no other host. Two mechanisms in package.json customize what gets installed:

resolutions overrides the version of a transitive dependency.

yarn patch applies the patches in .yarn/patches to a package after it is fetched. .yarn/patches/README.md describes each patch and how to add another.

A package that ships without TypeScript types gets its declarations in src/@types, e.g. page-lifecycle.d.ts, rather than being replaced by a typed fork.

Read the original README

KEEP EXPLORING

Also worth a look.

Keep good tools on your radar.

Short demos. New discoveries. Less noise in your feed.

Follow The StackRadar
THE STACKRADAR WALKTHROUGH

Tool demo

Tool details Open tool

Watch here, then explore the project's source for current details.