# cobbfan9/cobbfan9.github.io architecture

> Architecture diagram of the GitHub repository cobbfan9/cobbfan9.github.io, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-11-11). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/cobbfan9/cobbfan9.github.io
- Repository: https://github.com/cobbfan9/cobbfan9.github.io

## Overview

This is a browser-based SWGoH tools site. Its primary workflow is the portrait maker: users supply an image, configure portrait attributes and framing, generate a preview, then export it. Separate tool branches provide asset extraction, localization-bundle comparison, game-data comparison, SWGoH update information, and update-frequency charts. The graph follows documented routing and sampled imports/calls; some feature internals are represented by their exact source directories because their implementation was not sampled.

Main entry points: [`src/pages.tsx`](https://github.com/cobbfan9/cobbfan9.github.io/blob/main/src/pages.tsx) (Page routes), [`src/pages/portrait-maker.tsx`](https://github.com/cobbfan9/cobbfan9.github.io/blob/main/src/pages/portrait-maker.tsx) (Portrait page), [`src/pages/asset-extractor-web.tsx`](https://github.com/cobbfan9/cobbfan9.github.io/blob/main/src/pages/asset-extractor-web.tsx) (Asset extractor), [`src/pages/update-freq.tsx`](https://github.com/cobbfan9/cobbfan9.github.io/blob/main/src/pages/update-freq.tsx) (Update frequency)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_site["Site shell"]
  node_app["App shell<br/>[App.tsx]"]
  node_routes["Page routes<br/>[pages.tsx]"]
end

subgraph group_portrait["Portrait maker"]
  node_portrait_page["Portrait page<br/>[portrait-maker.tsx]"]
  node_portrait_input["Image input<br/>[upload-image.tsx]"]
  node_portrait_config["Portrait settings"]
  node_portrait_context["Portrait state<br/>[context.ts]"]
  node_portrait_render["Portrait renderer<br/>[swgohPortrait.tsx]"]
  node_portrait_export["Preview and export<br/>[export.tsx]"]
end

subgraph group_assets["Asset tools"]
  node_asset_page["Asset extractor"]
  node_asset_manifest["Asset manifest<br/>[manifest.tsx]"]
  node_asset_viewer["Asset viewer<br/>[asset-viewer.tsx]"]
  node_asset_loading["Loading status<br/>[loading-assets.tsx]"]
  node_asset_worker["Bundle worker<br/>[bundle-worker.ts]"]
  node_asset_studio["Asset Studio"]
end

subgraph group_data["Game data tools"]
  node_loc_page["Localization diff<br/>[loc-bundle.tsx]"]
  node_loc_loader["Bundle loader<br/>[loader.ts]"]
  node_loc_diff["Bundle comparison<br/>[diff-view.tsx]"]
  node_gamedata_page["Game-data diff<br/>[gamedata-diff.tsx]"]
end

subgraph group_updates["Updates"]
  node_updates_page["SWGoH updates<br/>[swgoh-updates.tsx]"]
  node_frequency_page["Update frequency<br/>[update-freq.tsx]"]
  node_frequency_chart["Frequency chart<br/>[grapher.tsx]"]
  node_frequency_data["Update retrieval<br/>[getUpdates.ts]"]
end

node_user(("Visitor"))

node_user -->|"opens site"| node_app
node_app -->|"selects route"| node_routes
node_routes -->|"loads page"| node_portrait_page
node_routes -->|"loads page"| node_asset_page
node_routes -->|"loads page"| node_loc_page
node_routes -.->|"loads page"| node_gamedata_page
node_routes -->|"loads page"| node_updates_page
node_routes -->|"loads page"| node_frequency_page
node_portrait_page -->|"renders input"| node_portrait_input
node_portrait_page -->|"renders settings"| node_portrait_config
node_portrait_page -->|"provides state"| node_portrait_context
node_portrait_page -->|"renders preview"| node_portrait_render
node_portrait_page -->|"renders export"| node_portrait_export
node_portrait_input -->|"updates state"| node_portrait_context
node_portrait_input -.->|"fetches assets"| node_asset_page
node_portrait_config -->|"updates settings"| node_portrait_context
node_portrait_config -->|"uses portrait"| node_portrait_render
node_portrait_export -->|"reads state"| node_portrait_context
node_asset_page -->|"shows manifest"| node_asset_manifest
node_asset_page -->|"shows asset"| node_asset_viewer
node_asset_page -->|"shows status"| node_asset_loading
node_asset_manifest -.->|"selects asset"| node_asset_viewer
node_asset_viewer -->|"opens bundle"| node_asset_worker
node_asset_worker -->|"extracts textures"| node_asset_studio
node_loc_page -->|"loads bundles"| node_loc_loader
node_loc_page -->|"renders comparison"| node_loc_diff
node_frequency_page -->|"renders chart"| node_frequency_chart
node_frequency_page -->|"gets updates"| node_frequency_data
node_frequency_page -->|"provides state"| node_frequency_chart

click node_app "https://github.com/cobbfan9/cobbfan9.github.io/blob/main/src/App.tsx"
click node_routes "https://github.com/cobbfan9/cobbfan9.github.io/blob/main/src/pages.tsx"
click node_portrait_page "https://github.com/cobbfan9/cobbfan9.github.io/blob/main/src/pages/portrait-maker.tsx"
click node_portrait_input "https://github.com/cobbfan9/cobbfan9.github.io/blob/main/src/components/portrait-maker/upload-image.tsx"
click node_portrait_config "https://github.com/cobbfan9/cobbfan9.github.io/blob/main/src/components/portrait-maker/configure-portrait.tsx"
click node_portrait_context "https://github.com/cobbfan9/cobbfan9.github.io/blob/main/src/ts/portrait-maker/context.ts"
click node_portrait_render "https://github.com/cobbfan9/cobbfan9.github.io/blob/main/src/components/swgohPortrait.tsx"
click node_portrait_export "https://github.com/cobbfan9/cobbfan9.github.io/blob/main/src/components/portrait-maker/export.tsx"
click node_asset_page "https://github.com/cobbfan9/cobbfan9.github.io/blob/main/src/pages/asset-extractor-web.tsx"
click node_asset_manifest "https://github.com/cobbfan9/cobbfan9.github.io/blob/main/src/components/asset-extractor/manifest.tsx"
click node_asset_viewer "https://github.com/cobbfan9/cobbfan9.github.io/blob/main/src/components/asset-extractor/asset-viewer.tsx"
click node_asset_loading "https://github.com/cobbfan9/cobbfan9.github.io/blob/main/src/components/asset-extractor/loading-assets.tsx"
click node_asset_worker "https://github.com/cobbfan9/cobbfan9.github.io/blob/main/src/ts/asset-extractor/bundle-worker.ts"
click node_loc_page "https://github.com/cobbfan9/cobbfan9.github.io/blob/main/src/pages/loc-bundle.tsx"
click node_loc_loader "https://github.com/cobbfan9/cobbfan9.github.io/blob/main/src/ts/loc-bundle/loader.ts"
click node_loc_diff "https://github.com/cobbfan9/cobbfan9.github.io/blob/main/src/components/loc-bundle/diff-view.tsx"
click node_gamedata_page "https://github.com/cobbfan9/cobbfan9.github.io/blob/main/src/pages/gamedata-diff.tsx"
click node_updates_page "https://github.com/cobbfan9/cobbfan9.github.io/blob/main/src/pages/swgoh-updates.tsx"
click node_frequency_page "https://github.com/cobbfan9/cobbfan9.github.io/blob/main/src/pages/update-freq.tsx"
click node_frequency_chart "https://github.com/cobbfan9/cobbfan9.github.io/blob/main/src/components/update-freq/grapher.tsx"
click node_frequency_data "https://github.com/cobbfan9/cobbfan9.github.io/blob/main/src/ts/update-freq/getUpdates.ts"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_app,node_routes toneBlue
class node_portrait_page,node_portrait_input,node_portrait_config,node_portrait_context,node_portrait_render,node_portrait_export toneAmber
class node_asset_page,node_asset_manifest,node_asset_viewer,node_asset_loading,node_asset_worker,node_asset_studio toneMint
class node_loc_page,node_loc_loader,node_loc_diff,node_gamedata_page toneRose
class node_updates_page,node_frequency_page,node_frequency_chart,node_frequency_data,node_user toneIndigo
```

## Components

### Site shell

- [App shell](https://github.com/cobbfan9/cobbfan9.github.io/blob/main/src/App.tsx): `src/App.tsx`
- [Page routes](https://github.com/cobbfan9/cobbfan9.github.io/blob/main/src/pages.tsx): `src/pages.tsx`

### Portrait maker

- [Portrait page](https://github.com/cobbfan9/cobbfan9.github.io/blob/main/src/pages/portrait-maker.tsx): `src/pages/portrait-maker.tsx`
- [Image input](https://github.com/cobbfan9/cobbfan9.github.io/blob/main/src/components/portrait-maker/upload-image.tsx): `src/components/portrait-maker/upload-image.tsx`
- [Portrait settings](https://github.com/cobbfan9/cobbfan9.github.io/blob/main/src/components/portrait-maker/configure-portrait.tsx): `src/components/portrait-maker/configure-portrait.tsx`
- [Portrait state](https://github.com/cobbfan9/cobbfan9.github.io/blob/main/src/ts/portrait-maker/context.ts): `src/ts/portrait-maker/context.ts`
- [Portrait renderer](https://github.com/cobbfan9/cobbfan9.github.io/blob/main/src/components/swgohPortrait.tsx): `src/components/swgohPortrait.tsx`
- [Preview and export](https://github.com/cobbfan9/cobbfan9.github.io/blob/main/src/components/portrait-maker/export.tsx): `src/components/portrait-maker/export.tsx`

### Asset tools

- [Asset extractor](https://github.com/cobbfan9/cobbfan9.github.io/blob/main/src/pages/asset-extractor-web.tsx): `src/pages/asset-extractor-web.tsx`
- [Asset manifest](https://github.com/cobbfan9/cobbfan9.github.io/blob/main/src/components/asset-extractor/manifest.tsx): `src/components/asset-extractor/manifest.tsx`
- [Asset viewer](https://github.com/cobbfan9/cobbfan9.github.io/blob/main/src/components/asset-extractor/asset-viewer.tsx): `src/components/asset-extractor/asset-viewer.tsx`
- [Loading status](https://github.com/cobbfan9/cobbfan9.github.io/blob/main/src/components/asset-extractor/loading-assets.tsx): `src/components/asset-extractor/loading-assets.tsx`
- [Bundle worker](https://github.com/cobbfan9/cobbfan9.github.io/blob/main/src/ts/asset-extractor/bundle-worker.ts): `src/ts/asset-extractor/bundle-worker.ts`
- **Asset Studio**

### Game data tools

- [Localization diff](https://github.com/cobbfan9/cobbfan9.github.io/blob/main/src/pages/loc-bundle.tsx): `src/pages/loc-bundle.tsx`
- [Bundle loader](https://github.com/cobbfan9/cobbfan9.github.io/blob/main/src/ts/loc-bundle/loader.ts): `src/ts/loc-bundle/loader.ts`
- [Bundle comparison](https://github.com/cobbfan9/cobbfan9.github.io/blob/main/src/components/loc-bundle/diff-view.tsx): `src/components/loc-bundle/diff-view.tsx`
- [Game-data diff](https://github.com/cobbfan9/cobbfan9.github.io/blob/main/src/pages/gamedata-diff.tsx): `src/pages/gamedata-diff.tsx`

### Updates

- [SWGoH updates](https://github.com/cobbfan9/cobbfan9.github.io/blob/main/src/pages/swgoh-updates.tsx): `src/pages/swgoh-updates.tsx`
- [Update frequency](https://github.com/cobbfan9/cobbfan9.github.io/blob/main/src/pages/update-freq.tsx): `src/pages/update-freq.tsx`
- [Frequency chart](https://github.com/cobbfan9/cobbfan9.github.io/blob/main/src/components/update-freq/grapher.tsx): `src/components/update-freq/grapher.tsx`
- [Update retrieval](https://github.com/cobbfan9/cobbfan9.github.io/blob/main/src/ts/update-freq/getUpdates.ts): `src/ts/update-freq/getUpdates.ts`

### Other components

- **Visitor**

## Connections

- Visitor → App shell: opens site
- App shell → Page routes: selects route (evidence: `src/App.tsx`)
- Page routes → Portrait page: loads page (evidence: `src/pages.tsx`)
- Page routes → Asset extractor: loads page (evidence: `src/pages.tsx`)
- Page routes → Localization diff: loads page (evidence: `src/pages.tsx`)
- Page routes → Game-data diff: loads page
- Page routes → SWGoH updates: loads page (evidence: `src/pages.tsx`)
- Page routes → Update frequency: loads page (evidence: `src/pages.tsx`)
- Portrait page → Image input: renders input (evidence: `src/pages/portrait-maker.tsx`)
- Portrait page → Portrait settings: renders settings (evidence: `src/pages/portrait-maker.tsx`)
- Portrait page → Portrait state: provides state (evidence: `src/pages/portrait-maker.tsx`)
- Portrait page → Portrait renderer: renders preview (evidence: `src/pages/portrait-maker.tsx`)
- Portrait page → Preview and export: renders export (evidence: `src/pages/portrait-maker.tsx`)
- Image input → Portrait state: updates state (evidence: `src/components/portrait-maker/upload-image.tsx`)
- Image input → Asset extractor: fetches assets
- Portrait settings → Portrait state: updates settings (evidence: `src/components/portrait-maker/configure-portrait.tsx`)
- Portrait settings → Portrait renderer: uses portrait (evidence: `src/components/portrait-maker/configure-portrait.tsx`)
- Preview and export → Portrait state: reads state (evidence: `src/components/portrait-maker/export.tsx`)
- Asset extractor → Asset manifest: shows manifest (evidence: `src/pages/asset-extractor-web.tsx`)
- Asset extractor → Asset viewer: shows asset (evidence: `src/pages/asset-extractor-web.tsx`)
- Asset extractor → Loading status: shows status (evidence: `src/pages/asset-extractor-web.tsx`)
- Asset manifest → Asset viewer: selects asset
- Asset viewer → Bundle worker: opens bundle (evidence: `src/components/asset-extractor/asset-viewer.tsx`)
- Bundle worker → Asset Studio: extracts textures (evidence: `src/ts/asset-extractor/bundle-worker.ts`)
- Localization diff → Bundle loader: loads bundles (evidence: `src/pages/loc-bundle.tsx`)
- Localization diff → Bundle comparison: renders comparison (evidence: `src/pages/loc-bundle.tsx`)
- Update frequency → Frequency chart: renders chart (evidence: `src/pages/update-freq.tsx`)
- Update frequency → Update retrieval: gets updates (evidence: `src/pages/update-freq.tsx`)
- Update frequency → Frequency chart: provides state (evidence: `src/pages/update-freq.tsx`)
