Documentation
User Guide
1. Open the application and drag & drop your GFF3 file into the drop zone on the Upload page, or click to select a file.
2. Once the file is uploaded, parsing begins automatically and mRNA features are extracted.
Supported File Formats:
- Extensions:
.gffor.gff3 - Format: GFF3 (Generic Feature Format version 3)
- Tab-delimited format
Note: The file must have a properly defined gene structure hierarchy (gene → mRNA → exon/CDS/UTR).
Once the file upload is complete, the search box becomes enabled.
Search Features:
Autocomplete:
Suggestions appear in real-time as you typeFuzzy Search:
Flexible search using Fuse.js (threshold: 0.5)Search Fields:
transcript_id, Parent attributeDisplay Limit:
Up to 20 results
Selected transcripts are displayed as badges and can be removed with the × button.
Click the "Generate Preview" button to create a gene structure diagram for the selected transcript.
Preview Screen Features:
SVG Viewer:
- Pan (drag to move)
- Zoom (mouse wheel)
- Auto-fit functionality
Color Customization:
- UTRs (5' and 3' untranslated regions)
- Exons (exons/CDS)
- Introns (intron lines)
Regenerate Button:
Click to regenerate the diagram after changing colors
Click the "Export" button to open the export settings dialog.
Export Options:
| Setting | Options | Description |
|---|---|---|
| Filename | Any text | Output filename (extension auto-appended) |
| Format | SVG / PNG | Output format selection |
| DPI (PNG only) | 72 / 150 / 300 / 600 | Image resolution (300+ recommended for publications) |
| Background (PNG only) | Transparent / White | Background color selection |
Technical Specifications
Library Used:
@gmod/gff (util.parseFeature)
The frontend uses the @gmod/gff library with streaming parsing for efficient memory usage on large files.
Parser Processing Flow:
// Streaming parser for GFF3 files
async function* parseGff3FileGenerator(file: File) {
const stream = file.stream();
const reader = stream.pipeThrough(new TextDecoderStream()).getReader();
// Parse line by line
while (true) {
const { done, value } = await reader.read();
if (done) break;
for (const line of lines) {
const feature = gffUtil.parseFeature(line);
// Process mRNA, exon, CDS, UTR features
}
}
yield* yieldGeneStructures(mRNAs);
}Data Type Definitions:
type Position = {
start: number;
end: number;
};
type GeneStructureInfo = GFF3FeatureLine & {
transcript_id: string;
total_length: number;
exons: Position[];
cds: Position[];
five_prime_utrs: Position[];
three_prime_utrs: Position[];
};Main Functions:
parseGff:
Uses FileReader to read file as string and parses with parseStringSyncgetmRNAs:
Traverses GFF3 hierarchical tree with depth-first search (DFS) to extract only mRNA featuresgetGeneStructureInfo:
Categorizes mRNA child features (exon, CDS, UTR) and converts to structured data
Implementation file: app/utils/gff.ts
This application consists of a Next.js frontend and FastAPI (Python) backend.
Endpoint List:
POST /api/py/generate-gene-structure-svg
Generates SVG image of gene structure (main API).
Request Body:
{
"draw_settings": {
"mode": "domain" | "gene",
"utr_color": "#d3d3d3",
"exon_color": "#000000",
"line_color": "#000000",
"intron_shape": "straight" | "zigzag",
"gene_height": number (optional),
"margin_x": number (optional),
"margin_y": number (optional)
},
"gene_structure": {
"transcript_id": "AT1G01010.1",
"seq_id": "Chr1",
"strand": "+" | "-",
"start": number,
"end": number,
"total_length": number,
"exons": [{ "start": number, "end": number }],
"cds": [{ "start": number, "end": number }],
"five_prime_utrs": [{ "start": number, "end": number }],
"three_prime_utrs": [{ "start": number, "end": number }]
}
}Response:
- Content-Type:
image/svg+xml - Body: SVG format image data
POST /api/py/draw-gene
Draws gene structure directly from GFF file (legacy API).
Request Body:
{
"transcript_id": "AT1G01010.1",
"gff_file_path": "./path/to/file.gff",
"deletion_regions": [[start, end], ...],
"domains": [
{
"start": number,
"end": number,
"name": "domain name",
"color": "#hexcolor"
}
],
"protein_domain_start": number (optional),
"protein_domain_end": number (optional),
"protein_domain_name": string (optional)
}GET /
Health check endpoint.
Response:
{ "message": "health check" }POST /api/upload-gff
Handles file uploads to Vercel Blob Storage (currently unused).
Features:
- File upload using Vercel Blob Client API
- Allowed content types: application/gff3, text/plain
- Token generation before upload (onBeforeGenerateToken)
- Callback processing on upload completion (onUploadCompleted)
Note: This API is not currently used as GFF parsing is done client-side.
Deployment Configuration (vercel.json):
{
"builds": [
{ "src": "api/index.py", "use": "@vercel/python" },
{ "src": "package.json", "use": "@vercel/next" }
],
"routes": [
{ "src": "/api/py/(.*)", "dest": "api/index.py" },
{ "src": "/(.*)", "dest": "/$1" }
]
}Python API documentation: /api/py/docs
Implementation files: api/index.py, app/api/upload-gff/route.ts
The backend Python (FastAPI) uses the svgwrite library to generate SVG images.
Main Classes:
GeneFeature
class GeneFeature:
def __init__(self, seqid, start, end,
feature_type, strand, attributes=None):
self.seqid = seqid
self.start = start
self.end = end
self.feature_type = feature_type
self.strand = strand
self.attributes = attributes or {}Class representing individual gene features (exon, CDS, UTR, etc.)
GeneStructure
class GeneStructure:
def __init__(self, gene_id, seqid, strand):
self.gene_id = gene_id
self.seqid = seqid
self.strand = strand
self.features = []
def add_feature(self, feature: GeneFeature)
def get_sorted_features(self)
def add_introns(self)
def to_relative(self)
def add_domains(self, domain_regions)
def update_features_with_deletions(self, deletion_regions)Class managing entire gene structure with feature addition and coordinate transformation
Main Drawing Function Processes:
Coordinate Relativization:
to_relative() converts to relative coordinates based on minimum coordinateScaling:
shrink_factor (default 30.0) compresses coordinates, scale parameter adjusts drawing sizeMinus Strand Support:
When strand = "-", coordinates are converted to negative valuesAutomatic Intron Generation:
Intron regions automatically calculated from exon/CDS/UTR gaps
Drawing Elements:
| Element | SVG Element | Default Settings |
|---|---|---|
| Exon/CDS | rect | fill: exon_color, stroke: black, stroke-width: 1 |
| UTR | rect | fill: utr_color, stroke: black, stroke-width: 1 |
| Intron | line | stroke: line_color, stroke-width: 1 |
| Domain | rect | fill: domain_color, stroke: black, stroke-width: 1 |
| Deletion | rect | fill: none, stroke: red, stroke-dasharray: "5,5" |
Automatic Legend Generation:
A legend is automatically added to the right side of the SVG, allowing visual understanding of each element's meaning.
Implementation file: api/index.py (lines 258-395)
Main Technology Stack:
Next.js:
React frameworkMantine UI:
UI component librarySWR:
Data fetching and cachingFuse.js:
Fuzzy search enginereact-svg-pan-zoom:
SVG viewer componentreact-dropzone:
File upload
State Management:
// UI state
const [uiState, setUiState] = useState<UIState>("upload" | "preview");
// File & data state
const [selectedFile, setSelectedFile] = useState<File | null>(null);
const [geneStructures, setGeneStructures] = useState<GeneStructureInfo[]>([]);
const [selectedTranscripts, setSelectedTranscripts] = useState<string[]>([]);
// Drawing settings
const [utrColor, setUtrColor] = useState("#d3d3d3");
const [exonColor, setExonColor] = useState("#000000");
const [lineColor, setLineColor] = useState("#000000");
// SVG data caching with SWR
const { data: svgData, mutate: mutateSVG } = useSWR(
["/api/py/generate-gene-structure-svg", getRequestData()],
() => postFetcher("/api/py/generate-gene-structure-svg", getRequestData())
);Processing Flow:
- File drop → parseGff() → getmRNAs() → getGeneStructureInfo()
- Search input → Fuse.js fuzzy search → autocomplete suggestions
- Transcript selection → add to selectedTranscripts array
- "Generate Preview" click → SWR API request → receive SVG
- Color change → "Regenerate" click → SWR cache update → refetch
- "Export" click → PNG conversion (using Canvas API) → download
SVG Viewer Component:
// SvgViewer.tsx
<ReactSVGPanZoom
tool={tool}
onChangeTool={setTool}
value={value}
onChangeValue={setValue}
detectAutoPan={false}
background="#ffffff"
>
<svg>
<g dangerouslySetInnerHTML={{ __html: svgContent }} />
</svg>
</ReactSVGPanZoom>Implementation files: app/page.tsx, app/components/SvgViewer.tsx
