Skip to content

Commit 6579a07

Browse files
ndemiancclaude
andcommitted
Blog: "Bringing Back Atom's Magic: Live Package Hot-Reload in Atom++"
A publishable writeup of the package generator + hot-reload dev loop, with image/GIF placeholders at the key beats and a capture checklist in blog/images/README.md. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent cfe57b7 commit 6579a07

2 files changed

Lines changed: 190 additions & 0 deletions

File tree

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
---
2+
title: "Bringing Back Atom's Magic: Live Package Hot-Reload in Atom++"
3+
date: 2026-06-26
4+
tags: [atom-plus-plus, editor, hackability, developer-experience]
5+
---
6+
7+
# Bringing Back Atom's Magic: Live Package Hot-Reload in Atom++
8+
9+
![Hero: editing a package and watching the status bar update live, no reload](./images/hot-reload-hero.gif)
10+
<!-- HERO GIF (the money shot, ~6-10s, loop):
11+
Split view — extension.js on the left, status bar visible at the bottom.
12+
Change item.text in code, hit save, status bar updates instantly. Repeat 2-3 times
13+
with different values so the loop reads clearly. Keep it tight and looping.
14+
Suggested size: ~1200px wide. -->
15+
16+
There was a particular kind of joy in hacking on Atom. You'd open `init.coffee`, write a
17+
few lines, and your editor would *change* — right there, while you were using it. No
18+
rebuild, no restart, no second window. The editor was clay, and it was warm.
19+
20+
When Atom was sunset, that feeling mostly went with it. Modern editors are fast and
21+
powerful, but extending them tends to mean: scaffold a project, press F5, wait for a second
22+
"Extension Development Host" window to boot, make a change, then reload that window to see
23+
it. It works. It's just… cold. The loop is long enough that you stop experimenting.
24+
25+
So while building **Atom++** — an AI-native, hackable editor on the VS Code core — I wanted
26+
that warmth back. Two commands now do it:
27+
28+
- **`Atom++: Generate Package…`** — scaffold a real, runnable package in one step.
29+
- **`Atom++: Develop Package (Hot Reload)…`** — load it into the editor you're *already
30+
using*, and re-run it every time you save.
31+
32+
Here's what that feels like, and how it works.
33+
34+
## The loop, in ten seconds
35+
36+
Open the command palette and run **`Atom++: Generate Package…`**. Type a name —
37+
`hello-atom`.
38+
39+
![The Generate Package command in the command palette with the name prompt](./images/generate-package-palette.png)
40+
<!-- SCREENSHOT: command palette open showing "Atom++: Generate Package…" (or the name
41+
input box with "hello-atom" typed). Crop to the palette + a bit of editor for context. -->
42+
43+
Atom++ scaffolds a complete package:
44+
45+
```
46+
~/.atom-plus-plus/packages/hello-atom/
47+
├── package.json # manifest + a sample command
48+
├── extension.js # activate() / deactivate()
49+
├── README.md
50+
└── .vscode/launch.json # for the full F5 dev host, when you need it
51+
```
52+
53+
It opens `extension.js` and offers a button: **Develop (Hot Reload)**. Click it.
54+
55+
A `● dev: hello-atom` indicator lights up in the status bar, a `🚀 hello-atom` item appears,
56+
and your sample command is live.
57+
58+
![The status bar showing the live dev indicator and the package's own status item](./images/dev-status-bar.png)
59+
<!-- SCREENSHOT: zoom on the status bar — the "● dev: hello-atom" indicator next to the
60+
"🚀 hello-atom" item. A tight horizontal crop of just the status bar reads best. -->
61+
62+
Now the good part: change the status text in
63+
`extension.js`, hit save, and watch the status bar update **instantly**. No window reload.
64+
No flicker. The editor just becomes the new version of itself.
65+
66+
```js
67+
function activate(context) {
68+
const item = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left, 0);
69+
item.text = '$(rocket) hello-atom'; // ← change this, save, watch it update live
70+
item.show();
71+
context.subscriptions.push(item);
72+
}
73+
```
74+
75+
![GIF: editing item.text, saving, and the status bar item changing with no reload](./images/save-to-update.gif)
76+
<!-- GIF (close-up of the moment, ~4-6s, loop): show the cursor editing item.text from
77+
'$(rocket) hello-atom' to something else, Cmd+S, and the status bar item swapping
78+
text immediately. This is the core "wow" — keep it focused on code + status bar. -->
79+
80+
81+
That's the Atom loop. Write, save, see it. The distance between an idea and a working
82+
change collapses to almost nothing — which is exactly when you start trying things you
83+
otherwise wouldn't.
84+
85+
## How it works
86+
87+
VS Code's extension model loads each extension **once**. That's the right call for stability,
88+
but it's why the normal dev story is "reload the whole window." To get true hot-reload, you
89+
have to step outside that model a little — carefully.
90+
91+
Atom++ runs a small **dev loader** inside the running window. When you start developing a
92+
package, it does three things:
93+
94+
**1. Loads your code into the live editor.** Instead of registering your package as a
95+
formal extension, it compiles `extension.js` as a fresh module and calls its `activate()`
96+
directly — handing it a context object with a `subscriptions` array, just like the real
97+
extension API. Crucially, it wires the bare `require('vscode')` call to the real editor API,
98+
so your package talks to the actual editor it's running inside:
99+
100+
```js
101+
const m = new Module(mainPath, null);
102+
m.require = (id) => (id === 'vscode' ? vscode : baseRequire(id));
103+
m._compile(fs.readFileSync(mainPath, 'utf8'), mainPath);
104+
return m.exports; // -> { activate, deactivate }
105+
```
106+
107+
Building a *new* module each time is also what makes reloads clean: there's no stale cached
108+
copy to fight with.
109+
110+
**2. Watches the folder and re-runs on save.** A recursive file watcher fires on every `.js`
111+
change, debounced by 150ms so a burst of saves collapses into one reload. Each reload tears
112+
down the previous run before starting the next — it calls your `deactivate()` and disposes
113+
every subscription your last `activate()` registered, so status items, commands, and event
114+
listeners don't pile up:
115+
116+
```js
117+
function reload() {
118+
teardown(); // deactivate() + dispose all previous subscriptions
119+
activatePackage(); // fresh module, fresh activate()
120+
}
121+
```
122+
123+
That dispose-then-reactivate cycle is the whole trick. Because the editor's API hands back a
124+
disposable for everything you create, "undo the last version" is just "dispose what it
125+
registered." Hot-reload becomes a bookkeeping problem, not a magic one.
126+
127+
**3. Fails safely.** If your edit has a typo, the reload is caught: you get a one-line error
128+
toast and a full stack trace in an "Atom++ Packages" output channel, while the editor keeps
129+
running. Fix the typo, save, and it recovers on the next reload. You never lose your session
130+
to a bad keystroke — which, again, is what makes you brave enough to experiment.
131+
132+
![A caught reload error: the error toast plus the stack trace in the output channel](./images/reload-error.png)
133+
<!-- SCREENSHOT (optional but nice): introduce a deliberate typo, save, and capture the
134+
error toast + the "Atom++ Packages" output channel showing the stack trace. Shows the
135+
editor survived a broken edit. -->
136+
137+
138+
## The honest part
139+
140+
This isn't sorcery, and it has an edge. Hot-reload runs your package's **runtime code** —
141+
the body of `activate()`, where Atom-style packages did most of their work: registering
142+
commands, adding UI, reacting to events. That covers a lot.
143+
144+
What it can't hot-swap is anything declared **statically in the manifest** — keybindings,
145+
menus, settings schemas contributed via `package.json`. Those are read when an extension
146+
loads, not when its code runs. For those, the generated `.vscode/launch.json` is right
147+
there: press **F5** for a full Extension Development Host. The two paths complement each
148+
other — live-reload for the fast inner loop, F5 for the manifest-level stuff.
149+
150+
I think being clear about that boundary matters more than pretending it doesn't exist. The
151+
goal was never to fake Atom; it was to bring back the part of Atom that made the editor feel
152+
*alive* — and that part is the inner loop.
153+
154+
## Why this matters
155+
156+
Tooling shapes behavior. When extending your editor means a 20-second round trip, you do it
157+
rarely and deliberately. When it means save-and-see, you do it constantly, casually,
158+
playfully. You write a tiny command to scratch an itch. You tweak a status bar to show the
159+
thing you actually care about. You make the editor *yours* — which was always the whole
160+
point of Atom.
161+
162+
Atom++ is a bet that an editor can be both modern (the VS Code core, native AI, real
163+
performance) and warm (hackable, scriptable, live). Package hot-reload is a small feature,
164+
but it's the one that, the first time it worked, genuinely felt like the Atom golden days
165+
again.
166+
167+
Write, save, see it. Welcome back.
168+
169+
---
170+
171+
*Atom++ is an AI-native, hackable, Notepad++-powered editor for macOS, built on the MIT
172+
Code-OSS core. The package generator and hot-reload loader live in the `atom-hackability`
173+
extension, alongside the user init script and the Atom/Notepad++ keymap presets.*

‎blog/images/README.md‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Blog images — capture checklist
2+
3+
Drop the captured assets here with these exact filenames so the post resolves them.
4+
5+
| File | Type | What to capture | Notes |
6+
| --- | --- | --- | --- |
7+
| `hot-reload-hero.gif` | GIF (loop) | Split view: `extension.js` + status bar. Edit `item.text`, save, status bar updates live. Repeat 2–3 times. | The hero. ~6–10s, ~1200px wide, looping. |
8+
| `generate-package-palette.png` | PNG | Command palette showing **Atom++: Generate Package…**, or the name input with `hello-atom` typed. | Crop to palette + a little editor. |
9+
| `dev-status-bar.png` | PNG | Status bar close-up: `● dev: hello-atom` next to `🚀 hello-atom`. | Tight horizontal crop of just the status bar. |
10+
| `save-to-update.gif` | GIF (loop) | Close-up of editing `item.text` → `⌘S` → status item swaps text instantly. | The core "wow". ~4–6s, focused on code + status bar. |
11+
| `reload-error.png` | PNG | Deliberate typo → save → error toast + **Atom++ Packages** output channel stack trace. | Optional; shows the editor survives a bad edit. |
12+
13+
## Tips
14+
- Record GIFs at the same window size for visual consistency; keep them short and looping.
15+
- Use the **Atom++ One Dark** theme in the captures so the post matches the product.
16+
- For crisp text, capture on a Retina display and export at 2×, then size down in the post if needed.
17+
- Tools: macOS screen recording (⇧⌘5) → convert to GIF (e.g. Gifski), or a recorder like Kap.

0 commit comments

Comments
 (0)