Documentation

How BoxoLand turns a cube resolution into DNA sequences: the geometry model, the bond assignment algorithm, free energy filtering, plates and picklists.

Overview

BoxoLand designs DNA origami wireframe cube assemblies. You pick a resolution β€” how many cubes along X, Y and Z β€” and the app builds the corresponding lattice of wireframe cubes in 3D. Each cube is a DNA origami monomer whose 12 edges are DNA helix bundles; cubes stick to their neighbours through bonds: short single-stranded overhangs that extend from the edges of the two touching faces.

The pipeline is: resolution β†’ lattice β†’ interface detection β†’ bond assignment β†’ sequence export β†’ plate picklist. Everything below documents one of those stages.

Cube geometry & edge numbering

Every cube has 8 vertices and 12 edges numbered 1–12. The numbering is fixed across the whole app β€” it is what makes bond labels (B01–B12), sequence names, and interface tables line up.

GroupEdges
Bottom face 1 = bottom-front, 2 = bottom-right, 3 = bottom-back, 4 = bottom-left
Top face 5 = top-front, 6 = top-right, 7 = top-back, 8 = top-left
Vertical 9 = front-left, 10 = front-right, 11 = back-right, 12 = back-left

Edge n carries the bond label B + n zero-padded to two digits, so edge 7 β†’ B07. The canonical definition β€” vertex coordinates, face membership and interface mappings β€” lives in app/assets/config/edge_numbering.json. Toggle Show Edge Labels in the sidebar to see the numbers rendered on the model.

Assembly generation

The X / Y / Z Cubes inputs drive a triple loop over lattice sites. Each site gets a cube whose id is its coordinate string "x,y,z", and whose world position is site index Γ— spacing per axis. Spacing depends on the assembly style:

StyleSpacingMeaning
Face-to-Face cubeSize Γ— 1.3 Cubes meet face to face with room to draw the bonds between them.
Edge-to-Edge (hexamer) cubeSize Γ— √2 / 1.25 Diagonal block spacing. Only a centre cube (at even coordinates) and its 6 axis-adjacent neighbours are kept, giving 7-cube hexamer blocks.

After the lattice is built the group is re-centred on the origin, and the reference ground grid is rebuilt to match: one grid cell per cube spacing, spanning the assembly footprint plus a one-cell margin, placed just under the lowest cube. Change the resolution and the grid grows with it.

Performance: above 64 cubes (and with per-edge colour coding off) the renderer switches to instanced meshes β€” one draw call per edge slot instead of per cube β€” which is what keeps large lattices interactive.

Interface detection & families

An interface is a pair of cubes that touch face to face. Detection walks the cube list and, for each cube, checks the +x, +y and +z neighbour; using only the positive directions counts each interface exactly once. Interfaces are grouped into three families by the axis along which the cubes touch, because the two faces involved expose a different set of 4 edges each:

FamilyAxisCube 1 edgesCube 2 edges
Family 1 Front–Back (Y) [1, 5, 9, 10] [3, 7, 11, 12]
Family 2 Left–Right (X) [2, 6, 10, 11] [4, 8, 9, 12]
Family 3 Top–Bottom (Z) [5, 6, 7, 8] [1, 2, 3, 4]

Each interface therefore involves 4 bonds, and each cube edge can participate in two different families β€” which is why assignments are keyed edge_family (for example 10_2 = edge 10 acting in family 2). Edge/family slots that no interface uses are marked X (inert).

Bond assignment algorithm

Every one of the 4 edges of an interface gets one of 8 bond variants (V1–V8). Two cubes bind only if their facing edges carry the same variant, so the assignment is what encodes which cube docks with which. The goal is orthogonality: two different interfaces in the same family should not look alike, or cubes will bind in the wrong place.

1. The overlap constraint

Overlap between two interfaces is the number of positions (out of 4) where they share the same variant. The slider sets the ceiling:

maxOverlapCount = floor(maxOverlapPercent / 100 Γ— 4)
SettingShared bonds allowedEffect
0%0Every interface fully unique β€” hardest to satisfy.
25% default1Maximum practical diversity.
50%2Looser; easier on large assemblies.
75%3Weak orthogonality.
100%4Interfaces may be identical.

The constraint is checked pairwise within each family only β€” interfaces in different families use disjoint edge sets, so they cannot be confused with one another.

2. Randomised constraint satisfaction

Rather than solving the assignment exactly (the search space is 84 = 4096 combinations per interface), the app samples:

  1. Assign random variants to every interface in the assembly.
  2. Validate: no same-family pair may exceed maxOverlapCount, and β€” if energy filtering is on β€” every interface must fall inside the energy window.
  3. Reject and retry until a fully valid assignment is found, or the attempt budget runs out.
  4. Repeat to collect a pool of valid solutions (Number of Random Combinations controls how hard the search tries).
3. Picking the winner

From the pool, the solution with the lowest average pairwise overlap wins β€” satisfying the constraint is the floor, and this step maximises the margin above it.

4. Projecting onto cubes

The winning interface-level assignment is expanded into per-cube data: for each interface, the 4 variants are written to cube 1's edges and to cube 2's matching edges, so both partners carry the complementary pair. The result is cubeAssignments["x,y,z"].edgeAssignments["edge_family"] = "V3", which is what the 3D bond rendering, the sequence export and the plate picklist all read.

Bond assignments are saved with the assembly, so reopening a saved assembly restores them β€” including for Add to Plate and Export Sequences β€” without re-running the algorithm.

Hierarchical assembly

Hierarchical assembly lets you build a stage-2 lattice whose unit cell is itself a complete DNA origami cube assembly β€” the building block. This produces two-level structures: the building block encodes stage-1 bonds; the outer lattice encodes stage-2 bonds that must be orthogonal to the stage-1 ones so the two assembly levels do not interfere.

Selecting a building block

In the Building Block section of the sidebar, type the name of any saved assembly. Once selected the 3D viewport re-renders each super-cube position as a scaled-down replica of the building block, complete with its stage-1 bond overlays. Three rendering tiers keep large assemblies responsive:

  • < 2,000 sub-cubes β€” full per-cube detail (individual meshes).
  • 2,000 – 80,000 sub-cubes β€” global InstancedMesh: one draw call for all cylinder edges and one for all torus rings, regardless of assembly size.
  • > 80,000 sub-cubes β€” wireframe LOD: one merged LineSegments object for the entire scene, with a notification explaining the simplified view.
Stage-1 bond assignment (inside the building block)

Run Assign Bonds on the building block assembly itself first (before selecting it as a building block for a larger design). The algorithm assigns 4 bond variants (V1–V8) to each of the 4 edges on every face-to-face interface, subject to the maximum overlap constraint. The result is saved with the assembly and loaded automatically when you select it as a building block.

Stage-2 bond assignment (between building blocks)

With a building block selected, clicking Assign Bonds on the outer assembly runs a second bond-assignment pass that treats each building-block position as a single unit. The solver assigns 4 bond variants per stage-2 interface (i.e. per pair of adjacent building blocks) while simultaneously enforcing:

  1. Intra-stage-2 overlap β€” controlled by the main Maximum Overlap % slider: how similar any two stage-2 interfaces in the same family can be.
  2. Inter-stage orthogonality β€” controlled by the per-sub-cube bond-count dropdowns: how many bond positions in a stage-2 interface are allowed to reuse a variant that already appears in stage-1.

Stage-1 variants are extracted automatically from the saved building-block assignment via extractStage1Variants. The solver biases its random draws away from those variants for the first 70% of attempts, then falls back to the full V1–V8 pool if the constrained space is exhausted.

Per-sub-cube bond-count dropdowns

When a building block is selected the Stage 1 β†’ Stage 2 Orthogonality panel shows one dropdown (0–4, default 4) for every sub-cube on each interface face:

  • X-axis face β€” sub-cubes in the YZ plane of the building block, one per (y, z) position, repeated for each stage-2 X-axis interface.
  • Y-axis face β€” sub-cubes in the XZ plane, repeated for each stage-2 Y-axis interface.
  • Z-axis face β€” sub-cubes in the XY plane, repeated for each stage-2 Z-axis interface.

Setting a sub-cube to k means only the first k of the 4 bond pairs at that sub-cube position are drawn in the visualization (and counted in the overlap metric). Setting it to 0 hides all bonds for that sub-cube. The display card shows chosen / total (percentage) updating in real time.

Bond overlap analysis panel

After every successful bond assignment a compact panel appears in the bottom-right corner of the screen showing:

  • Intra-stage average overlap % β€” the mean pairwise overlap across all interface pairs within each family, expressed as a percentage of 4 edge positions. Colour coded: green < 15%, yellow 15–35%, red > 35%.
  • Per-family breakdown β€” X, Y, Z axes listed separately so you can see which axis is under-orthogonalised.
  • Inter-stage overlap % (hierarchical mode only) β€” the fraction of stage-2 bond positions that share a variant with stage-1. Zero means perfect orthogonality between levels.

The panel closes with the Γ— button and re-opens automatically on the next assignment run.

Free energy filtering

Orthogonality alone does not guarantee that interfaces are equally strong. Each (family, bond, variant) triple has a pre-computed Gibbs free energy from nearest-neighbour stacking energies of its DNA sequence, in kcal/mol.

  • An interface's energy is the sum of its 4 bonds.
  • With filtering enabled, a candidate interface is rejected unless its total sits inside your min–max window.
  • The modal shows the recommended range derived from all available sequences, and warns if your window is unreachable.
  • After assignment you get the mean Β± standard deviation and the min/max across interfaces β€” a tight spread means uniform interface strength, which translates into cleaner folding and assembly yield.

Tightening the energy window shrinks the pool of legal variant combinations, so a narrow window plus a low overlap percentage is the usual reason a search fails.

Sequence export

Export Sequences writes a CSV containing every oligo needed to fold and assemble the design. Per cube that is roughly 169 sequences:

  • ~145 core staples β€” the wireframe cube itself; identical for every cube.
  • 24 bond sequences β€” 12 edges Γ— 2, chosen from the assigned variant for each edge_family slot.

Bond names are resolved as F2F_F{family}_B{edge}_V{variant}, looked up in the bond library to get the DNA sequence, then matched against the master sequence table to recover plate/well/concentration metadata. Unassigned slots resolve to the inert X sequence so the strand count per cube stays constant.

Plates & picklists

The Plate Manager tab models physical 96-well (8Γ—12, rows A–H) and 384-well (16Γ—24, rows A–P) plates. Add to Plate puts one cube per well, either into wells you type in or via auto-fill of the next free wells; with multi-plate auto-fill, assemblies larger than a plate spill into freshly created plates.

Each well records the concentrations used to compute transfers:

target staple conc (nM) = excess Γ— scaffold conc
transfer volume (Β΅L)   = (target conc (nM) Γ— final volume (Β΅L)) / (source conc (Β΅M) Γ— 1000)

Export Picklist sends the plate to the server, which joins every sequence against the mother-plate specification and emits an acoustic-liquid-handler CSV with source plate/well, destination plate/well and transfer volume per row. Sequences missing from the mother plate fall back to your stated stock concentration and are flagged in the log.

Editing, nanoparticles & MEEP

  • Edit Mode β€” click individual cubes to select them and attach cargo.
  • Nanoparticles β€” place a particle inside a cube's cavity with a material, radius and colour; the tracker panel lists every cube and its particles, and supports batch add/remove across a selection.
  • Deleting cubes β€” hover a cube and press Delete to carve it out of the lattice. Deleted sites are stored with the design and excluded from interface detection, so bonds must be re-assigned after a change.
  • Export MEEP β€” emits a Python script describing cubes, nanoparticles, materials, source and field monitors for FDTD electromagnetic simulation in MEEP.

Import / Export round-trips the whole design as JSON β€” parameters, cube positions and neighbours, deleted sites, and bond assignments.

Accounts, saving & sharing

Sign-in is email + password. Without an account you can still explore: change the resolution, switch styles, edit or delete cubes, add nanoparticles, and browse public assemblies in the catalog. Account-only features β€” bond assignment, plates and picklists, sequence export and saving β€” prompt you to log in.

  • Save stores the assembly in the database against your account, bond assignments included, and puts you on its /assembly/:id URL. Saving again updates that record in place.
  • Catalog lists your assemblies plus everything published by others; filter by All / Public / My Saved / Local.
  • Publish flips an assembly public so it shows up in the shared catalog; unlist to make it private again.
  • Share mints a random token and returns a /shared/<token> link that renders a read-only view of the design.
  • Local assemblies are legacy designs still held in this browser's storage; use Import on the card to copy one into your account.

Because bond assignments live inside the saved design data, reopening an assembly restores the bonds directly β€” which is what lets Add to Plate work on an existing assembly without re-running the assignment.

Interaction reference

InputAction
Left-dragOrbit the camera
Right-dragPan
Scroll / middle-dragZoom
Arrow keysPan
Hover + Delete / BackspaceDelete the hovered cube
Click a bondShow its family, edge, variant and sequence
Click a cube (Edit Mode)Select it / open the nanoparticle dialog
Fullscreen buttonExpand the 3D viewport