Desk Lamp

approvedunreviewed

by ouatis

Room lights off, one lamp left on.

↓ 22 downloadsUpdated 6d agoMIT

Desk Lamp

Room lights off, one lamp left on.

Chinese | Japanese

Open Desk Lamp in Obsidian

Latest release Downloads MIT License

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: false switches a note off; focus: section pins 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.