Py2Web is an utility for people who create webpages. It allows embedding chess problems viewer into the webpages in a way similar to that in which the PGN viewers work. The difference is that Py2Web supports many features that PGN viewers don't, e.g.: idling (set-play, threat, series-movers), twins, fairy pieces, fairy effects (rebirth, piece color change etc).


Example #3 problem by V. Chepizhny >>153689. Feel free to test your problems.

Starting position
in popeye 'Pieces' clause format:

in popeye output format with optional {comments}:

(Protip: you can copy and paste both fields from olive)
(Protip2: click right/left parts of the diagram to play the solution forward/backward)

More examples

Something more complicated. View this page source to check the syntax (it is 100% popeye output format).

Twins, promotions, rebirth and promotion as result of the rebirth

C. J. Feather
Fairings (28/5), 2012-11
white Pb3 Bg1 Ra4 Ka2 black Pb6h2a3g7b5 Sb2f5 Bc5d7 Kd4 Re4
h#2 CouscousCirce + Isardam
b) bPg7→g4
a) 1.h2*g1=Q[+wBd8] Ra4-c4 2.Bc5-f8 Bd8*b6[+bPc1=Q] # b) bPg7-->g4 1.Sb2*a4[+wRg8] Bg1-e3 2.Re4-e7 Rg8*g4[+bPh1=S] #

Fairy piece (nightrider), T&M notation, color change, kobul king

You can temporary hide solution from solvers, it is stil working.
P. Tritten & D. Turevski
Julia's fairies, 2013/I, 7th Prize
ded. to D. Kostadinov
black Pg7f6b6g3g5a5a7 Kc2 Rc4 Bh1 Nb5
AntiAndernach + KoBulKings +
Show solution

Long series-helpmate with rook-locust and PWC

Note how empty comments are used to add linebreaks. Also you can add any static HTML in comments. Diamond-shaped rook-locust illustrates the usage of the glyphs attribute (see "Usage" below, here glyphs='{"lr":"d"}').
C. J. Feather
Fairings (22/11), 2012-02
white Pd2 Kd5 lrg5 black Kc1
PWC, Rook-Locust g5
1.Kc1-d1 2.Kd1-e2 3.Ke2*d2[+wPe2] 4.Kd2-e3 5.Ke3*e2[+wPe3] { } 6.Ke2-f3 7.Kf3*e3[+wPf3] 8.Ke3-f4 9.Kf4*g5[+wLRf4] 10.Kg5-h4 { } 11.Kh4-g3 12.Kg3*f4[+wLRg3] 13.Kf4-e3 14.Ke3-f2 15.Kf2-g1 { } 16.Kg1-h2 17.Kh2*g3[+wLRh2] 18.Kg3-f4 19.Kf4*f3[+wPf4] 20.Kf3-g4 { } 21.Kg4-f5 22.Kf5*f4[+wPf5] 23.Kf4-g5 24.Kg5-f6 25.Kf6*f5[+wPf6] { } 26.Kf5-g6 27.Kg6-f7 28.Kf7*f6[+wPf7] 29.Kf6-g7 30.Kg7-h8 f7-f8=Q # 1.Kc1-c2 2.Kc2*d2[+wPc2] 3.Kd2-c3 4.Kc3*c2[+wPc3] 5.Kc2-b3 { } 6.Kb3*c3[+wPb3] 7.Kc3-b4 8.Kb4*b3[+wPb4] 9.Kb3-a4 10.Ka4-b5 { } 11.Kb5*b4[+wPb5] 12.Kb4-a5 13.Ka5-b6 14.Kb6*b5[+wPb6] 15.Kb5-a6 { } 16.Ka6-b7 17.Kb7*b6[+wPb7] 18.Kb6-c7 19.Kc7*b7[+wPc7] 20.Kb7-c8 { } 21.Kc8-d7 22.Kd7*c7[+wPd7] 23.Kc7-d8 24.Kd8-e7 25.Ke7-f6 { } 26.Kf6*g5[+wLRf6] 27.Kg5-h6 28.Kh6-g7 29.Kg7*f6[+wLRg7] 30.Kf6-e7 d7-d8=Q #

Neat solution auto-formatting

Py2Web shrinked the solution from 29 lines output by Popeye down to 5 (well, ok, 7). Also using "notation" attribute (new in 0.14.10) to display the solution in figurine notation.
A. Selivanov
JT V. Kopyl- 50, 2007
1st Prize
white Qc2 Rh6e8 Ke1 Bf5h8 Sb2h5 black Pg2e2g3 Kd5 Bf1
1.Qc2-c7 ! zugzwang. 1...g2-g1=Q 2.Sh5-f6 + 2...Kd5-d4 3.Re8-d8 + 3...Kd4-e3 4.Qc7*g3 + 4...Qg1*g3 # 1...g2-g1=S 2.Bf5-e6 + 2...Kd5-e4 3.Be6-g4 + 3...Ke4-d5 4.Bg4-f3 + 4...Sg1*f3 # 1...g2-g1=R 2.Re8-e5 + 2...Kd5-d4 3.Re5*e2 + 3...Kd4-d5 4.Re2-d2 + 4...Bf1-d3 # 1...g2-g1=B 2.Qc7-a5 + 2...Bg1-c5 3.Re8-e5 + 3...Kd5-d4 4.Qa5-b4 + 4...Bc5*b4 #

Imitators and .large diagrams (new in ver. 0.14.7)

J. Lörinc
Imitator TT, 1996
5th Comm
white Gf7b2c4b5b6 black Kg5 Ge4c6 neutral If4
h#8.5 Imitator f1, Grasshoppers
a) { } 1...Gb5-d7[Ih6] 2.Kg5-g6[Ih7] Gd7-b5[If5] 3.Kg6-f6[Ie5] Gb6-b4[Ie3] 4.Kf6-f5[Ie2] Gc4-c7[Ie5] { } 5.Ge4-b7[Ib8] Gc7-c5[Ib6] 6.Kf5-e5[Ia6] Gb5-d7[Ic8] 7.Gb7-d5[Ie6] Gc5-a3[Ic4] 8.Ke5-d6[Ib5] Gd7-g7[Ie5] { } 9.Kd6-c5[Id4] Gf7-c4[Ia1] # b) Imitator f6 {If6 } 1...Gb5-b7[If8] 2.Kg5-f4[Ie7] Gf7-f3[Ie3] 3.Ge4-g4[Ig3] Gf3-f5[Ig5] 4.Kf4-e5[If6] Gb7-b5[If4] { } 5.Ke5-f6[Ig5] Gb6-b4[Ig3] 6.Kf6-e6[If3] Gb5-d7[Ih5] 7.Ke6-d6[Ig5] Gc4-a4[Ie5] 8.Kd6-c7[Id6] Gd7-b7[Ib6] { } 9.Kc7-b6[Ia5] Gb7-b5[Ia3] # c) Imitator g3 {Ig3 } 1...Gc4-c7[Ig6] 2.Kg5-f5[If6] Gc7-c5[If4] 3.Kf5-e6[Ie5] Gb5-b7[Ie7] 4.Gc6-c4[Ie5] Gc5-c3[Ie3] { } 5.Ke6-d6[Id3] Gb2-d4[If5] 6.Kd6-d7[If6] Gc3-c5[If8] 7.Kd7-c6[Ie7] Gd4-f4[Ig7] 8.Kc6-b5[If6] Gf7-a7[Ia6] { } 9.Ge4-g4[Ic6] Gc5-a5[Ia6] # d) Imitator c7 {Ic7 } 1...Gb6-b4[Ic5] 2.Kg5-h5[Id5] Gb5-d3[If3] 3.Kh5-g4[Ie2] Gc4-c7[Ie5] 4.Ge4-b7[Ib8] Gc7-c5[Ib6] { } 5.Kg4-g3[Ib5] Gb2-b5[Ib8] 6.Gc6-c4[Ib6] Gb4-b6[Ib8] 7.Kg3-f2[Ia7] Gb5-d5[Ic7] 8.Kf2-f1[Ic6] Gd5-b5[Ia6] { } 9.Gc4-e2[Ic4] Gc5-a7[Ia6] #


This is what you add to the <head> part of your document:

<script type="text/javascript" src="jquery-1.11.1.js"></script>
<script type="text/javascript" src="py2web.js"></script>
<link href="py2web.css" rel="stylesheet" type="text/css" />
Feel free to edit CSS to change the look.

This is what you add to the <body> part of your document where you want the diagram and solution widgets to be displayed:

<div class="p2w-diagram" id="myUniqueId" glyphs='{"g":"q1","du":"p2"}'>
	[Starting position (in popeye 'Pieces' clause format)]
<div class="p2w-solution" target="myUniqueId" full-move="wb" start-node="first" notation='{"S":"N"}'>
	[Solution (in popeye output format)]

.p2w-diagram attributes:

.p2w-solution attributes:

This is where you can find py2web files (with sources): Github/dturevski/py2web


Py2Web defines one useful JS method that you can call on your pages if you need more dynamics and flexibility.


It has no return value. It iterates through all children of the selector that have class .p2w-solution and replaces their content with the solution widget while also replacing the content of the corresponding .p2w-diagram elements with the diagram widget.
As you already may have guessed Py2Web calls


when the page has loaded. However, you can load problem content dynamically into some container later and then call


The live demo at the top of this page works in exactly this way. It dynamically creates .p2w-solution and .p2w-diagram elements based on values in the textboxes, nests them within '#demo' div and then calls Py2Web.init('#demo'). Here's the actual source code, jQuery-style:

$(document).ready(function() {
    $("button").click(function() {
                .attr('id', 'demo-board').html($("#py-pieces").val()))
                .attr('target', 'demo-board').html($("#py-output").val()))        

Commands in comments

Starting from version 0.14.10 you can change the default behaviour of Py2Web with some special comments:

Error handling

Is minimal as of yet. Syntax and semantic errors (if any) are logged in the javascript console. If something isn't working - check console (Ctrl+Shift+J in Chrome and FF).

Under the hood

Py2Web is a free software with open source code. The parser part of the Py2Web is written in JS/CC which is a lexer/parser generator. You may need to have a general knowledge of what a compiler-compiler is.

Updated: 2018-03-15