Have you ever wanted to embed a crystal structure visualization in your website? Oddly specific question, I know, but recently I found my wanting to do this. As you can see on my homepage, I have finally achieved success but it took a few days to work out the kinks. In order to make sure that no one else endures my pain, here is how you can do this in Markdown using html and 3Dmol.js.

Caveat: I’ve worked this out for Jekyll but I’m pretty sure the approach is extensible.

Step 1

Take your crystal structure file and convert it into a pdb file. I started out with an xsf but, in principle, you could start out from a [cif][https://www.iucr.org/resources/cif], VASP POSCAR, or any other crystal structure data file, for that matter. If you’re lucky, you might be starting out with a pdf file! You will need to find a software package that converts your file into a pdb. Some packages you might consider are VESTA, Avogadro, and Mercury; all of these are free. If you’re willing to shell out, you could also get CrystalMaker. For reference, I’ve used CrystalMaker and here is the pdb I generated. This structure is an Ag10O7 overlayer that happens to form on the Ag(111) surface in an O2 atmosphere. For more information on this system and the ab initio grand canonical Monte Carlo method I used to find it, check out my recent paper in the Journal of Physical Chemistry C.

Step 2

Now you need to process your pdf file. It turns out that the JavaScript software that we will use, i.e. 3Dmol.js, requires all line breaks to be written as \n. Instead of doing this by hand, here’s how you can do it on the command line:

awk '{printf "%s\\n", $0}' <path to file> | sed "s/'/\\\'/g"

Hold on to this output, we will need it in a moment.

Step 3

OK, last but not least, now for the html and JavaScript part. First, I’ll present the code and then I’ll go line by line.

<html>
<head>
<script src="/3Dmol-min.js">
</script>
</head>
<div id="container-01" class="mol-container">
</div>
<style>
.mol-container {
  width: 60%;
  height: 400px;
  position: relative;
}
</style>
<script>
$(function() {
	let element = $('#container-01');
	let config = { backgroundColor : 'white' };
	let viewer = $3Dmol.createViewer( element, config );
	viewer.addModel("HEADER    5934-refined    \nREMARK   1\nREMARK   1 This file was generated by CrystalMaker X for macOS\nREMARK   1 http://crystalmaker.com\nREMARK   1\nCRYST1   11.452   11.452   28.630 120.00 120.00  60.00 P 1\nSCALE1      0.087322 -0.050415  0.035649        0.00000\nSCALE2     -0.000000  0.100830  0.035649        0.00000\nSCALE3      0.000000  0.000000  0.042779        0.00000\nATOM      1 Ag   MOL H   0      -0.716  -0.414   1.199  1.00  0.00          Ag0 \nATOM      2 Ag   MOL H   0       0.715   2.066   1.199  1.00  0.00          Ag0 \nATOM      3 Ag   MOL H   0       2.147   4.545   1.199  1.00  0.00          Ag0 \nATOM      4 Ag   MOL H   0       3.578   7.025   1.199  1.00  0.00          Ag0 \nATOM      5 Ag   MOL H   0       2.147  -0.414   1.199  1.00  0.00          Ag0 \nATOM      6 Ag   MOL H   0       3.578   2.066   1.199  1.00  0.00          Ag0 \nATOM      7 Ag   MOL H   0       5.010   4.545   1.200  1.00  0.00          Ag0 \nATOM      8 Ag   MOL H   0       6.441   7.024   1.200  1.00  0.00          Ag0 \nATOM      9 Ag   MOL H   0       5.010  -0.414   1.199  1.00  0.00          Ag0 \nATOM     10 Ag   MOL H   0       6.441   2.066   1.200  1.00  0.00          Ag0 \nATOM     11 Ag   MOL H   0       7.873   4.545   1.200  1.00  0.00          Ag0 \nATOM     12 Ag   MOL H   0       9.304   7.024   1.200  1.00  0.00          Ag0 \nATOM     13 Ag   MOL H   0       7.873  -0.414   1.199  1.00  0.00          Ag0 \nATOM     14 Ag   MOL H   0       9.304   2.066   1.200  1.00  0.00          Ag0 \nATOM     15 Ag   MOL H   0      10.735   4.546   1.200  1.00  0.00          Ag0 \nATOM     16 Ag   MOL H   0      12.167   7.025   1.198  1.00  0.00          Ag0 \nATOM     17 Ag   MOL H   0      -2.141  -1.237   3.524  1.00  0.00          Ag0 \nATOM     18 Ag   MOL H   0      10.737   1.253   3.505  1.00  0.00          Ag0 \nATOM     19 Ag   MOL H   0      12.151   3.730   3.541  1.00  0.00          Ag0 \nATOM     20 Ag   MOL H   0      13.597   6.208   3.515  1.00  0.00          Ag0 \nATOM     21 Ag   MOL H   0       0.723  -1.242   3.534  1.00  0.00          Ag0 \nATOM     22 Ag   MOL H   0       2.148   1.280   3.508  1.00  0.00          Ag0 \nATOM     23 Ag   MOL H   0       3.598   3.729   3.539  1.00  0.00          Ag0 \nATOM     24 Ag   MOL H   0       5.010   6.225   3.528  1.00  0.00          Ag0 \nATOM     25 Ag   MOL H   0       3.568  -1.243   3.534  1.00  0.00          Ag0 \nATOM     26 Ag   MOL H   0       5.010   1.253   3.504  1.00  0.00          Ag0 \nATOM     27 Ag   MOL H   0       6.446   3.725   3.562  1.00  0.00          Ag0 \nATOM     28 Ag   MOL H   0       7.872   6.199   3.529  1.00  0.00          Ag0 \nATOM     29 Ag   MOL H   0       6.431  -1.239   3.524  1.00  0.00          Ag0 \nATOM     30 Ag   MOL H   0       7.874   1.261   3.508  1.00  0.00          Ag0 \nATOM     31 Ag   MOL H   0       9.303   3.724   3.565  1.00  0.00          Ag0 \nATOM     32 Ag   MOL H   0      10.734   6.224   3.532  1.00  0.00          Ag0 \nATOM     33 Ag   MOL H   0       2.146   7.821   5.863  1.00  0.00          Ag0 \nATOM     34 Ag   MOL H   0      -2.108   0.399   5.777  1.00  0.00          Ag0 \nATOM     35 Ag   MOL H   0      -0.680   2.905   5.881  1.00  0.00          Ag0 \nATOM     36 Ag   MOL H   0      12.149   5.404   5.834  1.00  0.00          Ag0 \nATOM     37 Ag   MOL H   0      -0.700  -2.024   5.870  1.00  0.00          Ag0 \nATOM     38 Ag   MOL H   0       0.765   0.444   5.779  1.00  0.00          Ag0 \nATOM     39 Ag   MOL H   0       2.150   2.947   5.884  1.00  0.00          Ag0 \nATOM     40 Ag   MOL H   0       3.593   5.404   5.828  1.00  0.00          Ag0 \nATOM     41 Ag   MOL H   0       6.488   6.909   8.311  1.00  0.00          Ag0 \nATOM     42 Ag   MOL H   0       3.536   0.443   5.783  1.00  0.00          Ag0 \nATOM     43 Ag   MOL H   0       4.978   2.904   5.878  1.00  0.00          Ag0 \nATOM     44 Ag   MOL H   0       6.430   5.409   5.833  1.00  0.00          Ag0 \nATOM     45 Ag   MOL H   0       4.991  -2.025   5.876  1.00  0.00          Ag0 \nATOM     46 Ag   MOL H   0       6.411   0.399   5.779  1.00  0.00          Ag0 \nATOM     47 Ag   MOL H   0       7.874   2.993   5.951  1.00  0.00          Ag0 \nATOM     48 Ag   MOL H   0       9.287   3.968   8.340  1.00  0.00          Ag0 \nATOM     49  O   MOL H   0       2.158   5.468   8.890  1.00  0.00           O0 \nATOM     50  O   MOL H   0      -0.673   2.555   8.172  1.00  0.00           O0 \nATOM     51  O   MOL H   0       7.873   5.432   8.890  1.00  0.00           O0 \nATOM     52  O   MOL H   0      -0.699  -1.560   8.187  1.00  0.00           O0 \nATOM     53 Ag   MOL H   0      -0.682   0.497   8.155  1.00  0.00          Ag0 \nATOM     54 Ag   MOL H   0       0.779   3.991   8.329  1.00  0.00          Ag0 \nATOM     55  O   MOL H   0       5.001  -1.568   8.199  1.00  0.00           O0 \nATOM     56 Ag   MOL H   0       9.312   5.411   5.833  1.00  0.00          Ag0 \nATOM     57  O   MOL H   0       4.987   2.545   8.172  1.00  0.00           O0 \nATOM     58 Ag   MOL H   0       0.758   6.929   8.312  1.00  0.00          Ag0 \nATOM     59 Ag   MOL H   0       4.992   0.487   8.157  1.00  0.00          Ag0 \nATOM     60 Ag   MOL H   0       6.482   3.954   8.341  1.00  0.00          Ag0 \nATOM     61 Ag   MOL H   0       9.259   6.908   8.315  1.00  0.00          Ag0 \nATOM     62 Ag   MOL H   0       3.540   3.989   8.324  1.00  0.00          Ag0 \nATOM     63 Ag   MOL H   0       3.545   6.935   8.304  1.00  0.00          Ag0 \nATOM     64 Ag   MOL H   0       2.146  -2.050   5.892  1.00  0.00          Ag0 \nATOM     65  O   MOL H   0       7.878   1.176   7.076  1.00  0.00           O0 \n", "pdb");
	viewer.addUnitCell();
	viewer.setStyle({}, {sphere : {}});
	viewer.render();
});
</script>
</html>

Woah, nelly! It looks like a lot but it really isn’t. Everything is sandwiched between the html tags. Between the head tags is a script tag that contains the path to a minimal implementation of 3Dmol.js, which can be found here. 3Dmol.js contains different functions for reading, configuring, and plotting molecules and crystal structures. The div tag defines a container that will hold the crystal structure and the style tag defines its size. For example, we set the height to be 400 px and the width to be 60% of the that.

Finally, we get to the meat of the script where we pass the structure and define how we would like it plotted. The first and second lines of the function link to the container and set the background color to white, respectively. The third line reads these settings and creates a viewer, our molecular canvas, per say. Now’s the time where we add the structure. The addModel method has two arguments: (1) a string containing the contents of the crystal structure file and (2) a string identifying what type of file it is. The reason I chose to use pdb files is because pbd was the only file type I recognized that contained information about periodicity. Armed with the output of your awk command, add it between the two double quotes in the first argument below:

viewer.addModel("", "pdb")

As a final touch, the setStyle command, unsurprisingly, sets the atom/bond style; here, I have chosen to represent atoms by spheres with radii equal to their vdW radii (for more choices, follow this link). The last line of the code renders the image. I have copied the code below this text and it should produce the same image on my homepage.

Brilliant! There seem to be a ton of other things that you can do with 3Dmol.js. Have fun!