AgentStack
SKILL verified BSD-3-Clause Self-run

Experiment Design

skill-neuromechanist-research-skills-experiment-design · by neuromechanist

Use this skill for \"design experiment\", \"create PsychoPy experiment\", \"stimulus presentation\", \"experiment protocol\", \"timing validation\", \"trial structure\", \"block design\", \"event-related design\", \"PsychoPy builder\", \"create stimuli\", \"LSL markers\", \"Lab Streaming Layer\", \"event markers\", \"trigger codes\", or when the user wants to design or implement a neuroscience ex…

No reviews yet
0 installs
12 views
0.0% view→install

Install

$ agentstack add skill-neuromechanist-research-skills-experiment-design

✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

Are you the author of Experiment Design? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Experiment Design

Design and implement neuroscience experiments with PsychoPy, including stimulus presentation, timing validation, event markers, and Lab Streaming Layer (LSL) integration.

When to Use

  • Designing a new behavioral or neuroimaging experiment
  • Creating PsychoPy scripts for stimulus presentation
  • Setting up event markers via LSL or parallel port
  • Validating timing accuracy
  • Converting an experiment protocol to code

Experiment Design Principles

Trial Structure

Every trial consists of:

[Fixation] -> [Stimulus] -> [Response Window] -> [Inter-trial Interval]
   |              |               |                    |
  marker       marker          marker              marker

Design Types

| Design | Best For | Example | |--------|----------|---------| | Block | fMRI, sustained attention | 30s blocks of condition A, B | | Event-related | ERP/EEG, rapid events | Randomized single trials | | Mixed | Both sustained and transient | Blocks with jittered events | | Resting state | Baseline/connectivity | Eyes open/closed periods |

Timing Considerations

  • Frame-based timing (preferred): Specify durations in frames, not seconds
  • Monitor refresh rate: 60 Hz = 16.67 ms/frame; 120 Hz = 8.33 ms/frame
  • Stimulus onset: Sync to vertical blank for precise timing
  • Jitter: Add random ITI variation for event-related designs (avoid expectation effects)
  • Minimum stimulus duration: 1 frame (16.67 ms at 60 Hz)

PsychoPy Experiment Template

Basic Structure

from psychopy import visual, core, event, data, gui
import numpy as np

# Experiment parameters
exp_info = {
    "participant": "",
    "session": "01",
    "task": "experiment_name",
}

# GUI dialog
dlg = gui.DlgFromDict(exp_info, title="Experiment")
if not dlg.OK:
    core.quit()

# Window setup
win = visual.Window(
    size=[1920, 1080],
    fullscr=True,
    monitor="testMonitor",
    units="deg",
    color=[0, 0, 0],
)

# Stimuli
fixation = visual.TextStim(win, text="+", height=2)
stimulus = visual.ImageStim(win, image=None, size=[10, 10])
feedback = visual.TextStim(win, text="", height=1.5)

# Trial handler
conditions = data.importConditions("conditions.xlsx")
trials = data.TrialHandler(
    conditions,
    nReps=1,
    method="random",
)

# Clock
clock = core.Clock()

# Main experiment loop
for trial in trials:
    # Fixation
    fixation.draw()
    win.flip()
    core.wait(0.5)  # 500 ms fixation

    # Stimulus
    stimulus.image = trial["stimulus_file"]
    stimulus.draw()
    win.flip()
    # Send marker here

    # Response
    clock.reset()
    keys = event.waitKeys(
        maxWait=2.0,
        keyList=["left", "right", "escape"],
        timeStamped=clock,
    )

    if keys:
        if keys[0][0] == "escape":
            core.quit()
        trials.addData("response", keys[0][0])
        trials.addData("rt", keys[0][1])

    # ITI (jittered)
    iti = np.random.uniform(0.8, 1.2)
    core.wait(iti)

# Save data
import os
os.makedirs("data", exist_ok=True)
trials.saveAsWideText(f"data/sub-{exp_info['participant']}_task-{exp_info['task']}.csv")
win.close()
core.quit()

Conditions File Format

# conditions.xlsx or conditions.csv
stimulus_file,condition,correct_response
stimuli/face01.png,face,left
stimuli/house01.png,house,right
stimuli/face02.png,face,left

Lab Streaming Layer (LSL) Integration

Sending Markers

from pylsl import StreamInfo, StreamOutlet

# Create marker stream
info = StreamInfo(
    name="ExperimentMarkers",
    type="Markers",
    channel_count=1,
    nominal_srate=0,  # irregular rate
    channel_format="string",
    source_id="psychopy_markers",
)
outlet = StreamOutlet(info)

# Send marker at stimulus onset
stimulus.draw()
win.flip()
outlet.push_sample(["stimulus_onset"])  # Send immediately after flip

Common Marker Scheme

| Marker | Code | Description | |--------|------|-------------| | stimulusonset | S1-S99 | Stimulus presentation | | response | R1-R4 | Participant response | | feedback | F1-F2 | Correct/incorrect feedback | | blockstart | B1-B10 | Block onset | | blockend | BE | Block offset | | trialstart | T | Trial onset | | experimentstart | EXPSTART | First trial | | experimentend | EXPEND | Last trial |

HED Annotation for Markers

Annotate events with Hierarchical Event Descriptors (HED) for standardized event description:

onset	duration	trial_type	value	HED
0.0	0.0	stimulus	S1	Sensory-event, Visual-presentation, (Image, Face)
1.5	0.0	response	R1	Agent-action, (Press, Key/Left)

Timing Validation

Photodiode Check

# Add a small white square in the corner that flashes with stimulus
photodiode = visual.Rect(win, width=50, height=50, pos=[900, -500], units="pix")

# During stimulus presentation
stimulus.draw()
photodiode.fillColor = [1, 1, 1]  # White
photodiode.draw()
win.flip()
# Photodiode sensor on screen corner measures actual onset time

Frame Timing Check

# Check for dropped frames
win.recordFrameIntervals = True
# After experiment:
frame_intervals = win.frameIntervals
dropped = sum(1 for fi in frame_intervals if fi > 1.5 * (1.0 / 60.0))
print(f"Dropped frames: {dropped}/{len(frame_intervals)}")

Output for BIDS

Structure experiment output to be BIDS-compatible:

data/
  sub-01/
    sub-01_task-name_events.tsv    # onset, duration, trial_type, response, rt
    sub-01_task-name_beh.tsv       # behavioral data
    sub-01_task-name_beh.json      # metadata

Additional Resources

  • Reference: [references/psychopy-components.md](references/psychopy-components.md) - Visual, audio, and response components
  • Reference: [references/lsl-integration.md](references/lsl-integration.md) - LSL setup, synchronization, and troubleshooting

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet — be the first.

Versions

  • v0.1.0 Imported from the upstream source.