An Obsidian plugin that dims everything except the line, sentence, paragraph, or section you are working on.
The rest of the note falls back at an opacity you set. Granularity can be pinned per note through frontmatter, scoped to folders, and lines holding an embed, a formula, or a table always stay lit. The on/off state is remembered across restarts, and the ribbon icon shows it.
[!NOTE] Reading view is deliberately not supported. There is no caret there, so the focus has to be guessed from where you last were, and dimming most of a document while you are reading it makes the document harder to read. The feature was built, tried, and removed.
Install
Requires Obsidian 1.5.0 or newer.
From Obsidian: enable community plugins, then open Settings → Community plugins → Browse and search for Desk Lamp. The listing lives at community.obsidian.md/plugins/desklamp.
Manual, if you prefer: download main.js, manifest.json and styles.css
from the
latest release and put
them in <vault>/.obsidian/plugins/desklamp/, then enable it under
Settings → Community plugins.
With BRAT: add ouatis/obsidian-desklamp
as a plugin source (only useful for trying unreleased versions).
Features
- Four granularities — line, sentence, paragraph (the whole soft-wrapped paragraph), section (up to the next heading of the same level)
- Per-note overrides — frontmatter
focus: falseswitches a note off;focus: sectionpins its granularity without touching anything else. Chinese granularity names work too:行/句/段落/小节 - Scope rules — limit to certain folders, exclude others
- Never dims lines holding an embed, a formula or a table
- Multi-caret — every caret computes its own lit range
- Opacity slider 0–1, and a 0–500 ms transition that respects
prefers-reduced-motion - Ribbon icon shows the state: outline when off, filled when on
- Adopts the opacity from a previously installed focus plugin, so switching over is not a jump
Where it stops
CodeMirror's line decorations are line-granular, so sentence granularity lights the lines a sentence occupies — a line holding three sentences lights all three. Splitting inside a line needs mark decorations, which reads oddly for a focus tool (half a sentence bright, half dim).
Sentence splitting handles CJK and Western punctuation and avoids the usual
traps: the dot in 3.14, abbreviations like Mr. and e.g., single initials
like J. R., and treating ... as one boundary rather than three.
Commands
- Turn the lamp on / off
- Cycle granularity
- Diagnose: why is nothing dimmed
All three live in the command palette. The plugin ships without default hotkeys so it cannot collide with yours — assign shortcuts in Obsidian's keyboard settings if you want them.
If the lamp seems to do nothing, run Diagnose: why is nothing dimmed — it reports the whole chain (switch, granularity, note, scope, editors attached, lines actually carrying the decoration class) onto the clipboard and shows the verdict in a notice.
How it works
Desk Lamp uses a CodeMirror 6 ViewPlugin with line decorations. The lit set
is computed from EditorState on every selection change, and only the
visible lines outside it get a decoration class.
That means no global <body> class, no injected <style> element, and no DOM
walking — each editor instance owns its own state, so split panes and multiple
windows are handled per editor rather than globally.
Development
npm install
npm run dev # watch build
npm run typecheck
npm test # 49 engine tests
npm run build # production build
npm run test:bundle # 17 smoke tests against the built artifact
npm run verify # all of the above, then install into the vault
The engine tests import the real functions from src/engine.ts and run them
against real CodeMirror state and the real markdown parser, so they cannot
drift from the source. test/perf.mjs measures the per-keystroke cost.
Created by @ouatis. Inspired by Stille by Michael Lee. Ribbon icon from Phosphor Icons. Third-party notices: NOTICE.md.
For plugin developers
Search results and similarity scores are powered by semantic analysis of your plugin's README. If your plugin isn't appearing for searches you'd expect, try updating your README to clearly describe your plugin's purpose, features, and use cases.