Lux Betancourt46 downloadsDraw print-style Go (baduk, weiqi) diagrams in your notes: positions, numbered figures, interactive problems, and SGF files.
Go boards for Obsidian notes that look like the diagrams in a book: black ink, thin lines, numbered stones, nothing shiny. A board can be
Boards are stored as SGF, either right in the note or in an .sgf file the note points at.

(The pictures on this page were made with the plugin's test page, which imitates Obsidian's default theme.)
In Obsidian open Settings → Community plugins → Browse, search for Kifu, install it and switch it on.
To install it by hand instead, download main.js, manifest.json and styles.css from the latest release, put them in a folder <your vault>/.obsidian/plugins/kifu/, and switch Kifu on under Settings → Community plugins (press the refresh button next to Installed plugins if it is not listed).
Needs Obsidian 1.13 or later. It works on desktop, tablet and phone. It reads nothing outside your vault, and goes online only for games and problems you ask for (see below): when you import one from OGS or goproblems.com, or when a note is shown that embeds a link to a game or problem on a Go site or to an SGF file elsewhere. It then fetches that one game, problem or file, and nothing else is ever sent anywhere. The only time it looks through the vault's files is when you open the SGF file picker, which lists the .sgf files to choose from; a board reads only the file it points at.
To see everything at once, copy the two files in demo/ into your vault and open Kifu demo.
Run the command Kifu: Insert board (or right-click in the editor: Kifu → Insert 19 × 19 board, 13 × 13 or 9 × 9), or type the block yourself:
```kifu
```
That is an empty 19 × 19 board.
Esc, puts everything back.What a locked board shows:
numbers: line turns that into a numbered figure, and a move: line picks another position (move: 0 is the start). The ⚑ tool writes that line for you.While a board is unlocked the whole board is shown, with the part that will be hidden afterwards faded, and the moves carry their numbers (unless a numbers: line or the settings say otherwise).

| Tool | What it does |
|---|---|
| ① Play | Plays moves, alternating colours, and builds the tree: go back and play something else to add a variation. Click the tool again to change who plays next from here. |
| ● ○ Stones | Puts a stone down without it being a move (for setting up a position). Click a stone of the same colour to take it off. |
| △ □ ○ ✕ | Marks. They belong to the move you are on, so every move can carry its own. |
| A | Labels. The little box holds the next label: type a, A, 1, 51… and each click counts on from there. |
| Eraser | Removes a mark or label; a second click removes the stone under it. |
| Crop | Drag to choose the part of the board the locked board shows. Double-click (or double-tap) to go back to the automatic crop. |
| ⚑ Start | Makes the position on the board the one the locked board opens at, by writing a move: line. Click it again on that position to take the choice back. Only positions on the main line can be chosen: step there with ‹ › first. A problem chosen this way is solved from that position. |
| # | Makes the locked board a numbered figure of the main line, or takes the numbers off again. Whatever a numbers: line said before is put back, so a range like 51-100, or an off, is not lost by trying the switch. |
| ↶ | Undo (Ctrl/Cmd+Z while the board has the keyboard; Ctrl/Cmd+Shift+Z or Ctrl+Y redoes). |
| ‹ › | Previous / next move. |
| ✓ ✗ | Mark the line through this move as correct or incorrect. |
| ↑ | Move this variation up, towards being the main line. |
| 🗑 | Delete this move and everything after it. |
Two things worth knowing:
Comments are written in the move tree panel (see below).
A problem is a starting position plus the lines you saved from it.
On the locked board the solver's move is looked up in the tree. If it is there, a saved reply is played after a short pause (where you saved several, one of them at random, so the problem does not always answer the same way; the settings can make it always the first); if it is not, the move is simply incorrect. When a line ends a large ✓ or ✗ appears over the board for a moment, and the verdict and the line's comment stay underneath.
Stuck? The eye button under the lock shows the solution: the board starts over and plays out the first saved line judged correct, with the moves numbered, and the move tree panel shows all the saved lines. Step back through it with ‹ ›, or start over with ↺. (No ✓ appears for an answer that was shown rather than found.)

How a line is judged:
So the quickest way to write a problem is: enter the answer first, then the failures, and mark nothing.
SGF files from elsewhere work too. TE and BM are read as ✓ and ✗ (that is also what the plugin writes). So is a comment on a move that opens with "Correct", "Right", "Solved", "Success", "Wrong", "Incorrect" or "Fail…" as a word of its own, or that begins or ends with RIGHT in capitals, the way files from goproblems.com do.
A board is treated as a problem when its position was set up with stones of both colours and there are moves saved from it. Marks alone do not make one: a reviewed game has its good and bad moves marked too, and stays a game record. Say problem: yes or problem: no to decide yourself, or use the switch: the ? button under the lock while a board is unlocked, or Kifu → Problem board in the editor's right-click menu (for the board you right-clicked, or the block the cursor is in). The switch writes a problem: line only when the board would not decide the same by itself. A board that is not a problem still follows saved moves and answers them, but it does not judge by itself: only a line you marked ✓ or ✗ shows its verdict, once it has been played out to the end. With problem: no, nothing is judged at all.
To keep a problem from looking familiar, press the shuffle button under the lock while the board is unlocked (or write randomize: on). Each time the note is opened, the locked board is then shown turned or mirrored (any of the eight ways for a square board; a board that is not square is only mirrored), and half the time with the colours swapped, so a "Black to play" problem becomes "White to play". Captions and comments follow: "Black" and "White" in them change places. Only the picture changes: what you play is looked up as recorded, and unlocking shows the board the way it is written.
Press # while editing — or add numbers: on — and the locked board shows the main line played out with the stones numbered.
```kifu
numbers: on
(;GM[1]SZ[19];B[pd];W[nc];B[qf];W[pb];B[qc];W[kc])
```
For a stretch of a longer game, give the moves:
| Line | Shows |
|---|---|
numbers: on |
every move, numbered from 1 |
numbers: 51-100 |
the position after move 100, with moves 51–100 numbered 51–100 |
numbers: 51-100 from 1 |
the same stones numbered 1–50 |
numbers: on from 7 |
every move, the first one called 7 |
numbers: off |
no numbers on this board, not even while playing |
move: 50 |
just the position after move 50, no numbers |
A figure is drawn the way kifu are printed: a stone captured during the figure stays where it was, and a move played on an occupied point is listed underneath ("⑦ at ③"). As soon as you step through the moves or play on, you see the real position.
To number stones that are not moves — or to start anywhere you like — use the label tool and type the first number into its box.
By default a board is cropped to its stones (every variation counts), with two lines of margin, and snaps to the edge when the edge is close. Lines that run off a cut side are left open, as in print; real edges get the heavy border. Star points are drawn for any size.
Use the crop tool, or a view: line:
| Line | Shows |
|---|---|
view: full |
the whole board |
view: auto |
cropped to the stones |
view: top-right |
a corner (also top-left, bottom-left, bottom-right; tr, ne … work too) |
view: top |
a side (also bottom, left, right) |
view: center |
the middle |
view: top-right 9x7 |
a corner 9 columns wide and 7 rows tall |
view: top 6 |
the top six rows |
view: K10-T19 |
exactly this rectangle |
Board size comes from the SGF (SZ[13], SZ[19:13]). For a new board use size: 13 or size: 13x9, or change the default in the settings.
```kifu
sgf: [[Cho Chikun - Elementary.sgf]]
game: 12
```
sgf: takes a wikilink, a file name, or a path from the vault root or the note's folder. The command Kifu: Insert board from an SGF file, or Kifu → Display SGF file… in the editor's right-click menu, lets you pick one. Only .sgf files are ever used: a note that happens to have the same name is left alone.game: picks a game from a file that holds several (problem collections usually do). The first is 1.move: or numbers: to show another.Obsidian only lists .sgf files in its file explorer when Settings → Files and links → Detect all file extensions is on. If a board cannot find a file that is there, turn that setting on.
A base can show its notes as Kifu boards: choose it in the base's view menu, next to Table and Cards.
Each note gets a card with its first board, whichever comes first, a kifu block or an embedded link to a game or problem (see Boards from links), or, for an .sgf file in the base, its game; then its name and the properties you chose for the view, as in Cards.
sgf:) shows that file's game. A note with no board says so.This works wherever a base is shown: in a .base file, embedded with ![[Problems.base]], or in a base code block.
Embed a link to a game, review or puzzle on OGS, a problem on goproblems.com, a game on another Go server (see the list below), or an SGF file anywhere on the web, the way you would embed an image:




Instead of an image you get a board, fetched from the site each time the note is shown, in the reading view and in Live Preview (put the cursor on the link to edit it). A puzzle or problem can be solved on it and a game stepped through, like any other board, but nothing is ever written: to change one, import it instead (see below) and edit the copy in your note. A link that is shown again within a few minutes is not fetched again. A link to anything else stays an ordinary embed.
These links work, besides OGS and goproblems.com:
| Site | Link to embed |
|---|---|
| KGS | the game's SGF file from the game archive, https://files.gokgs.com/games/…/….sgf |
| Dragon Go Server | the game page, https://www.dragongoserver.net/game.php?gid=… |
| Fox (野狐) | the page its "share" button makes, https://h5.foxwq.com/yehunewshare/?chessid=… |
| GoQuest | the game record page, https://kifu.questgames.net/go/… (GoQuest keeps games for a while only) |
| Pandanet | an SGF file it offers, such as a tournament game (ordinary games are kept in its app) |
| Stone.gs | an OGS game it shows, https://stone.gs/games/ogs/… |
Games on Tygem, WBaduk and PlayGo, and problems on BlackToPlay and 101weiqi, can not be shown: these sites offer no record that can be fetched without signing in, or their terms forbid it.
An SGF file can be on a server of your own: any http or https link whose path ends in .sgf works (a query after it, such as an access key, is fine). It is treated like an SGF file in your vault: a problem is judged as one, a game record opens at its last move, and a file in an older charset (CA, such as Shift_JIS) is read in it. A server that asks you to sign in can not be used, since the plugin has no way to sign in.
Run Kifu: Import a game or puzzle from online-go.com (or right-click in the editor: Kifu → Import from online-go.com…) and paste a link to a game, a review (demo board) or a puzzle on OGS. A bare number works too: choose what it is under Kind.
Only public games, reviews and puzzles can be imported (OGS needs no account for them).
Run Kifu: Import a problem from goproblems.com (or right-click in the editor: Kifu → Import from goproblems.com…) and give the problem's number, or paste a link to it. The problem arrives where the cursor is, variations and comments included, as a board of its own with a link back to its page above it:
[goproblems.com #5](https://www.goproblems.com/problems/5) · Tesuji, 14 kyu, by adum
```kifu
problem: yes
(;AW[pe][pf]…
```
goproblems.com marks a correct line by ending its comment with RIGHT. On import that becomes a ✓ on the move (and the word leaves the comment), so the problem judges itself the way it does on the site.
Public problems need nothing more. To import problems that are not public, create an API token in your goproblems.com account and choose it under Settings → Kifu → Importing from goproblems.com. It is kept in Obsidian's secret storage, not in the plugin's settings file, and is sent only to goproblems.com, only with an import.
Network use: the plugin goes online only to fetch a game or problem you asked for: when you import one from OGS or goproblems.com, or when a note is shown that embeds a link to one (on those sites, the other Go servers listed above, or an SGF file anywhere). Each time it asks one place (the site the link is to, or for a Stone.gs link OGS) for that one game, problem or file, sending nothing but the request itself (and, for goproblems.com, your token if you chose one).
The panel lives in the right sidebar (command Kifu: Show move tree; on a computer it also comes forward when you unlock a board). It follows the board you last used and shows
While a problem is locked the panel keeps the answers to itself: it shows only the moves that are on the board. The eye button shows all the saved lines; starting over hides them again. (There is a setting for this. Stepping forward with → walks along a saved line, so that shows the answer too.)
With the keyboard on a board (click it) or on the panel:
| Key | |
|---|---|
← → |
previous / next move |
↑ ↓ |
previous / next variation |
Home End |
first position / end of the line |
Esc |
locked: back to the resting position · unlocked: lock · while dragging a crop: never mind |
Ctrl/Cmd+Z |
unlocked: undo · locked: take back your last step |
Ctrl/Cmd+Shift+Z, Ctrl+Y |
unlocked: redo · locked: make that step again |
In the panel's comment box every key belongs to the text you are typing, undo included.
While a board has the keyboard, what you type, paste or undo stays with the board and never reaches the note's text. Obsidian's own hotkeys keep working, though — including ones that act on the editor.
Option lines come first in the block, one per line, before any SGF.
| Option | Values | |
|---|---|---|
sgf |
link or path | take the game from a file |
game |
number | which game, when the file (or the block) holds several |
size |
19, 13x9 |
size of a board with no SGF yet |
view |
see above | part of the board to show |
move |
number, last |
position to show |
numbers |
see above | numbered figure |
scale |
80%, 1.5, fit |
size of this board (fit: as wide as the note, with lines as thin as at the usual size) |
coords |
on / off |
coordinates beside the board's edges (the real ones, where the part shown has any) |
caption |
text | text under the board at rest |
comments |
on / off |
show move comments under the board |
problem |
yes / no |
judge moves or not |
style |
paper / theme |
white paper, or the theme's colours |
align |
left / center / right |
|
randomize |
on / off |
show the board turned, mirrored and maybe recoloured, a new way each time the note opens |
Settings → Kifu holds the defaults: scale, colours, crop, coordinates, alignment, new board size, whether played moves are numbered, whether comments show under the board, how replies are chosen (a random saved answer, or always the first) and how long they wait, whether the panel hides a problem's answers, and whether unlocking brings the panel forward. Every one of them is only a default: an option line in a block wins.
The drawing is plain SVG coloured by CSS variables, so a snippet can restyle it:
.kifu {
--kifu-font: "Gill Sans", sans-serif; /* numbers and letters */
--kifu-ink: #111; /* lines, outlines, labels */
--kifu-paper: #fdfcf8; /* background */
--kifu-black: #111; /* black stones */
--kifu-white: #fff; /* white stones */
}
caption: line settles it. In the editor and the reading view this does not arise.)) is shown but cannot be edited, so that nothing after it gets swallowed. A game: line asking for a game the block does not have shows a message instead of a board.CA charset..sgf file does not update sgf: lines. Moving it to another folder is fine as long as the name stays unique.Version 1.0.0, the first public release. Besides being used in Obsidian on the desktop, it is checked automatically: the built plugin runs in a browser against a stand-in for the Obsidian API, with Live Preview played by a real CodeMirror editor, and on touch screens in Safari's engine (WebKit) as well as Chromium. Wherever Obsidian's behaviour is not documented, the checks are run with the stand-in behaving both ways. The part that writes into notes got the most attention: it was reviewed independently three times, and is exercised by a randomized test on top of the fixed scenarios.
Found a bug, or a board that looks wrong? Please open an issue, with the block's text if you can.
GNU General Public License v3.0.
npm install
npm run build # type-check and bundle main.js
npm test # unit tests: SGF, rules, sessions, finding blocks in Markdown
npm run test:browser # the built plugin in Chromium (once: npx playwright install chromium)
npm run test:monkey # randomized runs of the same, a few minutes
npm run lint # Obsidian's own lint rules
tests/*.test.ts — unit tests. markdown.test.ts checks the code that finds and rewrites a block against a CommonMark parser on thousands of generated notes.tests/harness/obsidian-mock.js — the stand-in for the Obsidian API; cm-lp.ts — Live Preview on a real CodeMirror 6.tests/harness/touch.mjs — taps on tablet and phone profiles, in WebKit (once: npx playwright install webkit) and Chromium.tests/harness/interact.mjs, editor.mjs, identity.mjs — the scenarios (the last one is all about boards that read the same, notes rearranged under a board, panes that are behind, and writes that fail); ONLY='pattern' in the environment runs the scenarios whose names match. perf.mjs — timings; shots.mjs, docs.mjs — pictures.tests/harness/monkey.mjs — a "monkey" that places and removes stones, marks and labels, types comments, locks, scrolls and (in its rougher profiles) edits the note by hand at the same time: types into blocks, deletes, copies and moves them, undoes, changes the file from outside. It does so in eight arrangements of panes and five kinds of note, most of them full of identical boards. After every step it checks that nothing is in a block other than the one whose board was used, and at the end that nothing outside the blocks changed, that every board shows what its block says, that no edit vanished without a notice, that none vanished at all from a block nobody had touched by hand, and that nothing typed by hand was taken back. node tests/harness/monkey.mjs live,both hands 1-10 runs chosen arrangements, profiles and seeds.x.y.z) in manifest.json and package.json, and add it to versions.json with the lowest Obsidian version it needs.git tag -a 1.0.1 -m "Kifu 1.0.1" && git push origin 1.0.1..github/workflows/release.yml) checks that the tag matches the manifest, builds, runs the unit tests and publishes the release with main.js, manifest.json and styles.css.git push.The order matters. Obsidian installs a plugin by reading manifest.json on the default branch and downloading the release with that version; if the branch names a version whose release does not exist yet, installing fails.