Subsections of Labs

Week 1: Pipetting

cover image cover image

Week 2: DNA Gel Art

cover image cover image

Design

Coming from a design background, I find it really interesting that DNA digestion patterns could be treated as a visual medium. I played around with Ronan’s gel art website trying different combination of digest results and I found some band patterns that generated a robot design. After I landed on the design, I used benchling to perform the virtual digest with the corresponding enzymes.

Design using Ronan’s website Design using Ronan’s website Ronan’s website allowed me to scroll through different enzyme combinations and randomize to see what patterns came up, which was much faster for exploring visual patterns.

Virtual digest in Benchling Virtual digest in Benchling Benchling virtual digest of my final 6-lane design, showing predicted band sizes for each enzyme combination against the 1 Kb Plus Thermo ladder.

Lane Assignments

My final design uses 6 lanes cut with different restriction enzyme combinations, mirrored across the center:

Lane assignments Lane assignments

Restriction Digest Preparation

Each digest reaction was prepared in a PCR tube with the following components:

Restriction digest recipe Restriction digest recipe *Reaction setup for each lane. Each tube contained water, CutSmart buffer, Lambda DNA, and the specific enzyme(s). *

The reactions were incubated at 37°C for 30 minutes to allow the enzymes to fully cut the DNA.

Lab Process

Step 1: Prepare the TAE buffer and agarose gel

We used 1× TAE buffer to mix with agarose powder. The flask was microwaved until the cloudy color became completely clear as the solution just bagan to have some bubbles.

Dissolving agarose in the microwave Dissolving agarose in the microwave Waiting for the solution to cool down

Step 2: Add DNA stain and pour the gel

Once the agarose cooled slightly, we added a small amount of SYBR Safe DNA stain which made the solution tinted pink.

SYBR Safe DNA stain SYBR Safe DNA stain The SYBR Safe stain next to the flask of melted agarose.

We then poured the gel into the casting tray with the comb in place and waited for it to solidify.

Poured gel solidifying in the tray Poured gel solidifying in the tray The gel cast in the electrophoresis tray with the comb creating wells at the top.

Step 3: Prepare the digest reactions

While waiting for the gel, we prepared the restriction digest reactions. Each tube was labeled 1-6 corresponding to our lane design. We pipetted water, CutSmart buffer, Lambda DNA, and the specific enzymes into each tube.

Preparing digest reactions Preparing digest reactions Pipetting enzymes and Lambda DNA stored on ice.

This was the most challenging part because the micropipetting was tricky. It was hard to tell whether we had the right amount, since the volumes are so small they’re essentially invisible in the pipette tip.

Labeled digest tubes Labeled digest tubes Six labeled digest tubes ready for incubation.

Step 4: Add loading dye and load the gel

After incubation, we added loading dye to each reaction which would help us visually track how far the gel has run.

Adding loading dye Adding loading dye Adding loading purple dye to the digest reactions before loading into the gel.

We then filled casting wells with 1x TAE and loaded 20 uL of each samples

Step 5: Run the gel

Once loaded, we connected the electrodes and started running the gel. We noticed bubbles in the TAE buffer when the elctricity is on.

Gel electrophoresis running Gel electrophoresis running The electrophoresis setup running.

Gel electrophoresis running Gel electrophoresis running Small bubbles rising to surface

We ran it for about 45 minutes to allow the DNA to travel more than halfway throught the gel.

Results

Gel result — printed from imager Gel result — printed from imager Printed gel image from the lab imager

Gel result — digital capture Gel result — digital capture Digital gel result

The symmetric design concept came through but the overall image was fainter and the lower section was not visible. Possible reasons might be too little DNA samples and shorter runtimes.

Week 3: Opentrons Art

cover image cover image

Design

I designed a mandala-inspired symmetrical pattern using the Opentrons Art Interface, drawing on the visual language of radial symmetry. The script was exported from the GUI and ran on the Opentrons software

Design in the Opentrons Art GUI Design in the Opentrons Art GUIDesign in the Opentrons Art GUI Design in the Opentrons Art GUI

Python Script

from opentrons import types
import string

metadata = {
    'protocolName': '{ANNIE} - Opentrons Art - HTGAA',
    'author': 'HTGAA',
    'source': 'HTGAA 2026',
    'apiLevel': '2.20'
}

Z_VALUE_AGAR = 2.0
POINT_SIZE = 0.75

mjuniper_points = [(-1,31), (1,31), (-13,27), (-11,27), (-1,27), (1,27), (11,27), (13,27), (-15,25), (-13,25), (-1,25), (1,25), (13,25), (15,25), (-5,21), (5,21), (-19,19), (-7,19), (-3,19), (3,19), (7,19), (19,19), (-27,17), (-19,17), (-1,17), (1,17), (19,17), (27,17), (-7,15), (7,15), (-23,13), (-21,13), (-19,13), (19,13), (21,13), (23,13), (-7,11), (7,11), (21,11), (-15,9), (15,9), (-19,7), (-17,7), (17,7), (19,7), (-5,5), (5,5), (-29,3), (29,3), (-31,1), (-29,1), (29,1), (31,1), (-31,-1), (-29,-1), (29,-1), (31,-1), (-29,-3), (29,-3), (-5,-5), (5,-5), (-19,-7), (-17,-7), (17,-7), (19,-7), (-15,-9), (15,-9), (-21,-11), (-7,-11), (7,-11), (21,-11), (-21,-13), (-19,-13), (19,-13), (21,-13), (-7,-15), (7,-15), (-27,-17), (-19,-17), (-1,-17), (1,-17), (19,-17), (27,-17), (-19,-19), (-7,-19), (-3,-19), (3,-19), (19,-19), (-5,-21), (5,-21), (-15,-25), (-13,-25), (-1,-25), (1,-25), (13,-25), (15,-25), (-13,-27), (-11,-27), (-1,-27), (1,-27), (11,-27), (13,-27), (-1,-31), (1,-31)]
mko2_points = [(-3,27), (3,27), (-11,25), (-5,25), (-3,25), (3,25), (5,25), (11,25), (-11,23), (-9,23), (-3,23), (3,23), (9,23), (11,23), (-15,21), (-11,21), (11,21), (15,21), (-15,19), (-13,19), (-1,19), (1,19), (13,19), (15,19), (-13,17), (13,17), (-23,15), (-21,15), (-19,15), (-11,15), (-5,15), (5,15), (11,15), (19,15), (21,15), (-27,13), (-11,13), (-7,13), (-3,13), (3,13), (7,13), (11,13), (27,13), (-25,11), (-5,11), (-3,11), (3,11), (5,11), (25,11), (-23,9), (-21,9), (-11,9), (-9,9), (-5,9), (-3,9), (3,9), (5,9), (9,9), (11,9), (21,9), (23,9), (-11,7), (-7,7), (-5,7), (-3,7), (3,7), (5,7), (7,7), (11,7), (-13,5), (-3,5), (-1,5), (1,5), (3,5), (13,5), (-25,3), (-3,3), (3,3), (25,3), (-27,1), (-25,1), (-23,1), (-11,1), (-9,1), (-7,1), (-5,1), (5,1), (7,1), (9,1), (11,1), (23,1), (25,1), (27,1), (-27,-1), (-25,-1), (-23,-1), (-11,-1), (-9,-1), (-7,-1), (-5,-1), (5,-1), (7,-1), (9,-1), (11,-1), (23,-1), (25,-1), (27,-1), (-25,-3), (-3,-3), (3,-3), (25,-3), (-13,-5), (-3,-5), (-1,-5), (1,-5), (3,-5), (13,-5), (-11,-7), (-7,-7), (-5,-7), (-3,-7), (3,-7), (5,-7), (7,-7), (-23,-9), (-21,-9), (-11,-9), (-9,-9), (-5,-9), (-3,-9), (3,-9), (5,-9), (9,-9), (11,-9), (21,-9), (23,-9), (-25,-11), (-5,-11), (-3,-11), (3,-11), (5,-11), (25,-11), (-27,-13), (-11,-13), (-7,-13), (-3,-13), (3,-13), (7,-13), (11,-13), (27,-13), (-21,-15), (-19,-15), (-11,-15), (-5,-15), (5,-15), (11,-15), (19,-15), (21,-15), (-13,-17), (13,-17), (-17,-19), (-15,-19), (-13,-19), (-1,-19), (13,-19), (15,-19), (-17,-21), (-15,-21), (-11,-21), (11,-21), (15,-21), (-11,-23), (-9,-23), (-3,-23), (3,-23), (9,-23), (11,-23), (-11,-25), (-5,-25), (-3,-25), (3,-25), (5,-25), (11,-25), (-3,-27), (3,-27)]
mrfp1_points = [(-3,31), (3,31), (-5,29), (-3,29), (-1,29), (1,29), (3,29), (5,29), (-17,27), (-15,27), (-7,27), (-5,27), (5,27), (7,27), (15,27), (17,27), (-17,25), (-7,25), (7,25), (17,25), (-17,23), (-15,23), (-7,23), (7,23), (15,23), (17,23), (-7,21), (7,21), (-11,19), (-9,19), (9,19), (11,19), (-25,17), (-23,17), (-17,17), (-15,17), (-11,17), (-9,17), (-7,17), (7,17), (9,17), (11,17), (15,17), (17,17), (23,17), (25,17), (-27,15), (-13,15), (-3,15), (3,15), (13,15), (23,15), (27,15), (-17,13), (-13,13), (-9,13), (9,13), (13,13), (17,13), (-27,11), (-23,11), (-13,11), (-11,11), (11,11), (13,11), (23,11), (27,11), (-25,9), (25,9), (-27,7), (-25,7), (-23,7), (-15,7), (-13,7), (13,7), (15,7), (23,7), (25,7), (27,7), (-29,5), (-25,5), (-23,5), (-17,5), (-15,5), (15,5), (17,5), (23,5), (25,5), (29,5), (-31,3), (-27,3), (-21,3), (-19,3), (-17,3), (-15,3), (-5,3), (5,3), (15,3), (17,3), (19,3), (21,3), (27,3), (31,3), (-21,1), (-19,1), (-13,1), (13,1), (19,1), (21,1), (-21,-1), (-19,-1), (-13,-1), (13,-1), (19,-1), (21,-1), (-31,-3), (-27,-3), (-21,-3), (-19,-3), (-17,-3), (-15,-3), (-5,-3), (5,-3), (15,-3), (17,-3), (19,-3), (21,-3), (27,-3), (31,-3), (-29,-5), (-25,-5), (-23,-5), (-17,-5), (-15,-5), (15,-5), (17,-5), (23,-5), (25,-5), (29,-5), (-27,-7), (-25,-7), (-23,-7), (-15,-7), (-13,-7), (13,-7), (15,-7), (23,-7), (25,-7), (27,-7), (-25,-9), (25,-9), (-27,-11), (-23,-11), (-13,-11), (-11,-11), (11,-11), (13,-11), (23,-11), (27,-11), (-17,-13), (-13,-13), (-9,-13), (9,-13), (13,-13), (17,-13), (-27,-15), (-23,-15), (-13,-15), (-3,-15), (3,-15), (13,-15), (23,-15), (27,-15), (-25,-17), (-23,-17), (-17,-17), (-15,-17), (-11,-17), (-9,-17), (-7,-17), (7,-17), (9,-17), (11,-17), (15,-17), (17,-17), (23,-17), (25,-17), (-11,-19), (-9,-19), (9,-19), (11,-19), (-7,-21), (7,-21), (-17,-23), (-15,-23), (-7,-23), (7,-23), (15,-23), (17,-23), (-17,-25), (-7,-25), (7,-25), (17,-25), (-17,-27), (-15,-27), (-7,-27), (-5,-27), (5,-27), (7,-27), (15,-27), (17,-27), (-5,-29), (-3,-29), (-1,-29), (1,-29), (3,-29), (5,-29), (-3,-31), (3,-31)]
mclover3_points = [(-5,23), (5,23), (-3,21), (3,21), (-17,19), (-5,19), (5,19), (17,19), (-25,15), (25,15), (-11,5), (11,5), (-9,3), (9,3), (-9,-3), (9,-3), (-11,-5), (11,-5), (11,-7), (-25,-15), (25,-15), (-5,-19), (1,-19), (5,-19), (17,-19), (-3,-21), (3,-21), (-5,-23), (5,-23)]
sfgfp_points = [(-21,11), (-23,-13), (23,-13)]

point_name_pairing = [("mjuniper", mjuniper_points),("mko2", mko2_points),("mrfp1", mrfp1_points),("mclover3", mclover3_points),("sfgfp", sfgfp_points)]

TIP_RACK_DECK_SLOT = 9
COLORS_DECK_SLOT = 6
AGAR_DECK_SLOT = 5
PIPETTE_STARTING_TIP_WELL = 'A1'

well_colors = {
    'A1': 'sfGFP', 'A2': 'mRFP1', 'A3': 'mKO2', 'A4': 'Venus',
    'A5': 'mKate2_TF', 'A6': 'Azurite', 'A7': 'mCerulean3', 'A8': 'mClover3',
    'A9': 'mJuniper', 'A10': 'mTurquoise2', 'A11': 'mBanana', 'A12': 'mPlum',
    'B1': 'Electra2', 'B2': 'mWasabi', 'B3': 'mScarlet_I', 'B4': 'mPapaya',
    'B5': 'eqFP578', 'B6': 'tdTomato', 'B7': 'DsRed', 'B8': 'mKate2',
    'B9': 'EGFP', 'B10': 'mRuby2', 'B11': 'TagBFP', 'B12': 'mChartreuse_TF',
    'C1': 'mLychee_TF', 'C2': 'mTagBFP2', 'C3': 'mEGFP', 'C4': 'mNeonGreen',
    'C5': 'mAzamiGreen', 'C6': 'mWatermelon', 'C7': 'avGFP', 'C8': 'mCitrine',
    'C9': 'mVenus', 'C10': 'mCherry', 'C11': 'mHoneydew', 'C12': 'TagRFP',
    'D1': 'mTFP1', 'D2': 'Ultramarine', 'D3': 'ZsGreen1', 'D4': 'mMiCy',
    'D5': 'mStayGold2', 'D6': 'PA_GFP'
}

volume_used = {
    'mjuniper': 0, 'mko2': 0, 'mrfp1': 0, 'mclover3': 0, 'sfgfp': 0
}

def update_volume_remaining(current_color, quantity_to_aspirate):
    rows = string.ascii_uppercase
    for well, color in list(well_colors.items()):
        if color == current_color:
            if (volume_used[current_color] + quantity_to_aspirate) > 250:
                row = well[0]
                col = well[1:]
                next_row = rows[rows.index(row) + 1]
                next_well = f"{next_row}{col}"
                del well_colors[well]
                well_colors[next_well] = current_color
                volume_used[current_color] = quantity_to_aspirate
            else:
                volume_used[current_color] += quantity_to_aspirate
            break

def run(protocol):
    protocol.home()
    tips_20ul = protocol.load_labware('opentrons_96_tiprack_20ul', TIP_RACK_DECK_SLOT, 'Opentrons 20uL Tips')
    pipette_20ul = protocol.load_instrument("p20_single_gen2", "right", [tips_20ul])
    temperature_plate = protocol.load_labware('opentrons_96_aluminumblock_generic_pcr_strip_200ul', 6)
    agar_plate = protocol.load_labware('htgaa_agar_plate', AGAR_DECK_SLOT, 'Agar Plate')
    agar_plate.set_offset(x=0.00, y=0.00, z=Z_VALUE_AGAR)
    center_location = agar_plate['A1'].top()
    pipette_20ul.starting_tip = tips_20ul.well(PIPETTE_STARTING_TIP_WELL)

    def dispense_and_jog(pipette, volume, location):
        assert(isinstance(volume, (int, float)))
        above_location = location.move(types.Point(z=location.point.z + 2))
        pipette.move_to(above_location)
        pipette.dispense(volume, location)
        pipette.move_to(above_location)

    def location_of_color(color_string):
        for well, color in well_colors.items():
            if color.lower() == color_string.lower():
                return temperature_plate[well]
        raise ValueError(f"No well found with color {color_string}")

    for i, (current_color, point_list) in enumerate(point_name_pairing):
        if not point_list:
            continue
        pipette_20ul.pick_up_tip()
        max_aspirate = int(18 // POINT_SIZE) * POINT_SIZE
        quantity_to_aspirate = min(len(point_list)*POINT_SIZE, max_aspirate)
        update_volume_remaining(current_color, quantity_to_aspirate)
        pipette_20ul.aspirate(quantity_to_aspirate, location_of_color(current_color))

        for i in range(len(point_list)):
            x, y = point_list[i]
            adjusted_location = center_location.move(types.Point(x, y))
            dispense_and_jog(pipette_20ul, POINT_SIZE, adjusted_location)
            if pipette_20ul.current_volume == 0 and len(point_list[i+1:]) > 0:
                quantity_to_aspirate = min(len(point_list[i:])*POINT_SIZE, max_aspirate)
                update_volume_remaining(current_color, quantity_to_aspirate)
                pipette_20ul.aspirate(quantity_to_aspirate, location_of_color(current_color))
        pipette_20ul.drop_tip()

Printing

The OT-2 dispensed 0.75 µL drops of each fluorescent strain onto the charcoal agar plate.

Opentrons OT-2 dispensing onto the agar plate Opentrons OT-2 dispensing onto the agar plate Printing in progress Printing in progress

Result

After overnight incubation, the plate was imaged under UV light.

Final plate under UV illumination Final plate under UV illumination

Week 6: Gibson Assembly

cover image cover image

Using PCR-based mutagenesis, Gibson Assembly, and bacterial transformation, we intended to introduce targeted mutations into the amilCP gene to produce magenta and blue color variants in E. coli.


Part 1: PCR

We ran two separate PCR reactions from the mUAV plasmid template using Phusion HF PCR Master Mix:

Backbone Fragment (Backbone Fwd + Backbone Rev primers): amplifies the origin of replication, chloramphenicol resistance gene, promoter, and RBS.

Color Insert Fragment (Color Fwd + Color Rev primers): amplifies the region from 24 bp before the chromophore to the terminator. The Forward primer contains a mutation at the CP site to introduce the desired color mutation(we chose magenta and blue variants).

Each reaction was run in a 25 µL volume with 0.8 µL template (38.5 ng/µL), 2.5 µL of each primer (5 µM stock), and 12.5 µL Phusion HF PCR Mix.

PCR reaction setup PCR reaction setupLabeled PCR tubes Labeled PCR tubes

Thermocycler conditions:

Backbone PCR: 98°C 30s → 26 cycles of (98°C 10s / 57°C 25s / 72°C 1.5 min) → 72°C 5 min → 12°C hold

Color PCR: 98°C 15s → 26 cycles of (98°C 10s / 53°C 20s / 72°C 15s) → 72°C 5 min → 12°C hold

Two Bio-Rad T100 thermocyclers running BB_PCR (left) and COLR_PCR (right) simultaneously Two Bio-Rad T100 thermocyclers running BB_PCR (left) and COLR_PCR (right) simultaneously

Part 1a: DNA Purification

PCR products were purified using the Zymo DNA Clean & Concentrator kit. Each 20µL sample was mixed with 100 µL DNA Binding Bufferinto micro centrifuge tube and loaded onto a ZymoSpin column, and centrifuged. After two washes with 200 µL DNA Wash Buffer, DNA was eluted in 6 µL nuclease-free water.

Zymo purification columns Zymo purification columns labeled PCR tubes prepared for cleanup labeled PCR tubes prepared for cleanup


Part 1b: Diagnostic Gel Electrophoresis

Purified samples were run on through gel electrophoresis to confirm correct fragment sizes. 2 µL of each sample was mixed with 18 µL of water and loaded into the gel wells along with 20µL of pre-diluted ladder and original mUAV plasmid as references.

Loading samples onto the E-Gel EX for electrophoresis Loading samples onto the E-Gel EX for electrophoresisGel result bands visible at expected sizes for backbone and color insert fragments Gel result bands visible at expected sizes for backbone and color insert fragments

Part 2a: Gibson Assembly

Purified backbone and color fragments were assembled using Gibson Assembly Master Mix. Reactions were set up in 10 µL total volume and incubated at 50°C for 15 minutes. After incubation, 100 µL of nuclease-free water was added to dilute the reaction before transformation.

Gibson Assembly works by: (1) exonuclease chewing back 5’ ends to expose complementary single-stranded overhangs, (2) annealing of complementary overhangs between backbone and insert, (3) polymerase filling in gaps, and (4) ligase sealing nicks to form a complete circular plasmid.


Part 2b: Transformation

Gibson Assembly products were transformed into DH5α chemically competent E. coli cells using heat shock:

  1. Thawed competent cells on ice for 10 minutes
  2. Added 4 µL of diluted Gibson Assembly product to 20 µL of competent cells
  3. Incubated on ice for 30 minutes Labeled transformation tubes incubating on ice Labeled transformation tubes incubating on ice
  4. Heat shocked at 42°C for exactly 45 seconds, then returned to ice for 5 minutes
  5. Added 100 µL SOC media and incubated with shaking for 60 minutes Tubes recovering in SOC media on orbital shaker for 60 minutes post heat shock Tubes recovering in SOC media on orbital shaker for 60 minutes post heat shock
  6. Plated 100 µL onto agar plates Plates stacked upside down and placed in 37°C incubator for 72 hours Plates stacked upside down and placed in 37°C incubator for 72 hours
  7. Incubated plates at 37°C for 72 hours Plates stacked upside down and placed in 37°C incubator for 72 hours Plates stacked upside down and placed in 37°C incubator for 72 hours

Results

result image result image result image result image result image result image All plates had very low colony count overall. The blue plate had 2 visibly blue-colored colonies, small partial success. Both magenta plates showed no magenta coloration, so the colonies that did grow were likely untransformed or reverted to original amilCP color of purple.

Week 7: Neuromorphic Circuits

IANN Circuit Design

Our group wanted to design a dual region neuromorphic circuit using all three ERNs. The circuit takes two inputs (X1 and X2) and produces mNeonGreen as the fluorescent output, with a bias providing a baseline level of output fluorescent mRNA.

The plasmid composition for each transfection group was as follows:

MyCircuit MyCircuit

The circuit has three mNeonGreen mRNA sources with different survival conditions:

  • PgU_rec_mNeonGreen (from X1) survives when PgU (X2) is low
  • Csy4_rec_mNeonGreen (from X2) survives when Csy4 (X1) is low
  • CasE_rec_mNeonGreen (Bias) survives when CasE is low, which happens when both X1 and X2 are high and mutually cancel each other’s CasE production

The behavior predicted under different input conditions:

X1 HIGH, X2 LOW: Csy4(from X1) destroys X2’s Csy4_rec_mNeonGreen. PgU is low, so PgU_rec_mNeonGreen from X1 survives. Result: high output.

X2 HIGH, X1 LOW: PgU(from X2) destroys X1’s PgU_rec_mNeonGreen. Csy4 is low, so Csy4_rec_mNeonGreen from X2 survives. Result: high output.

BOTH HIGH: Both direct mNeonGreen sources are destroyed. However, both ERNs also suppress each other’s CasE mRNAs, so CasE levels drop and the bias mRNA survives. Result: moderate output from bias only(will depend on bias level).

BOTH LOW: Little DNA overall, low expression across all components, and no ERN suppression means some CasE still gets made and cleaves the bias. Result: lowest output.

The circuit is therefore behaving as a Dual Region (Top-Left, Bottom-Right) circuit. Output is high when the two inputs are mismatched (one high, one low) and low when they are matched in either direction.

Predicted Output

MyCircuit Prediction Heatmap MyCircuit Prediction Heatmap

The prediction heatmap shows Dual Region behavior. High output appears in the top-left (X1 low, X2 high) and bottom-right (X1 high, X2 low) corners. The bottom-left (both low) is the minimum, and the top-right (both high) is moderate rather than high, reflecting the partial bias contribution when both ERNs cancel each other.

Experiment Results

Class Scatterplots - Low, Medium, High Bias Class Scatterplots - Low, Medium, High Bias

Each dot in the class scatterplots represents a single HEK293 cell. X-axis is X1 input (via mKO2), Y-axis is X2 input (via eBFP2), and dot color is mNeonGreen output intensity. The three panels show results at low, medium, and high bias DNA concentrations.

Low bias: Bright cells concentrate in the mismatched input regions (high X2 + low X1, or high X1 + low X2), consistent with the direct mNeonGreen mRNAs dominating. The pattern is clearly dual-region.

Medium bias: Output spreads more uniformly across the input space and dims overall. The bias is now competing with the direct mNeonGreen sources but not yet dominating, producing a flatter, less structured response.

High bias: The brightest cells shift toward the both-high region (top-right). With so much CasE_rec_mNeonGreen available, the dominant output source is now the bias when both ERNs are high and mutually suppress CasE production.