update docs

This commit is contained in:
2026-02-15 02:29:41 -08:00
parent d8cf83d517
commit a8682c33f2
20 changed files with 380 additions and 103 deletions

View File

@@ -5,6 +5,12 @@ export default {
title: 'SubMiner Docs',
description: 'All-in-one sentence mining overlay for MPV with AnkiConnect and dictionary integration',
base,
head: [
['link', { rel: 'icon', href: '/favicon.ico', sizes: 'any' }],
['link', { rel: 'icon', type: 'image/png', href: '/favicon-32x32.png', sizes: '32x32' }],
['link', { rel: 'icon', type: 'image/png', href: '/favicon-16x16.png', sizes: '16x16' }],
['link', { rel: 'apple-touch-icon', href: '/apple-touch-icon.png', sizes: '180x180' }],
],
appearance: 'dark',
cleanUrls: true,
lastUpdated: true,

View File

@@ -172,7 +172,7 @@ To mine multiple subtitle lines as one sentence card, use `Ctrl/Cmd+Shift+S` fol
## Field Grouping (Kiku)
When you mine the same word multiple times, SubMiner can merge the cards instead of creating duplicates. This is designed for note types like [Kiku](https://github.com/donkuri/Kiku) that support grouped sentence/audio/image fields.
When you mine the same word multiple times, SubMiner can merge the cards instead of creating duplicates. This is designed for note types like [Kiku](https://github.com/youyoumu/kiku) that support grouped sentence/audio/image fields.
```jsonc
"ankiConnect": {

View File

@@ -86,71 +86,51 @@ src/renderer/
```mermaid
flowchart TD
classDef root fill:#c6a0f6,stroke:#181926,color:#181926,stroke-width:2px;
classDef orchestration fill:#494d64,stroke:#b7bdf8,color:#cad3f5,stroke-width:2px;
classDef domain fill:#494d64,stroke:#8aadf4,color:#cad3f5,stroke-width:2px;
classDef boundary fill:#494d64,stroke:#a6da95,color:#cad3f5,stroke-width:2px;
classDef root fill:#c6a0f6,stroke:#24273a,color:#24273a,stroke-width:2px
classDef comp fill:#b7bdf8,stroke:#24273a,color:#24273a,stroke-width:1.5px
classDef svc fill:#8aadf4,stroke:#24273a,color:#24273a,stroke-width:1.5px
classDef ext fill:#a6da95,stroke:#24273a,color:#24273a,stroke-width:1.5px
subgraph Entry["Entrypoint"]
Main["src/main.ts\nentry point"]
Main["src/main.ts"]:::root
subgraph Composition["Composition Modules"]
Startup["Startup & Lifecycle"]:::comp
IpcCli["IPC & CLI Wiring"]:::comp
Overlay["Overlay & Shortcuts"]:::comp
Subsync["Subsync"]:::comp
end
class Main root;
subgraph MainModules["src/main/ Composition Modules"]
Startup["startup.ts\nbootstrap flow"]
AppLifecycle["app-lifecycle.ts\nlifecycle events"]
StartupLifecycle["startup-lifecycle.ts\napp-ready sequence"]
State["state.ts\nruntime state container"]
IpcRuntime["ipc-runtime.ts\nIPC handlers"]
CliRuntime["cli-runtime.ts\nCLI dispatch"]
OverlayRuntime["overlay-runtime.ts\nwindow/modal"]
SubsyncRuntime["subsync-runtime.ts\nsubsync orchestration"]
subgraph Services["Domain Services"]
OverlaySvc["Overlay Services"]:::svc
MpvSvc["MPV Stack"]:::svc
MiningSvc["Mining & Subtitles"]:::svc
ShortcutIpc["Shortcuts & IPC"]:::svc
end
class Startup,AppLifecycle,StartupLifecycle,State,IpcRuntime,CliRuntime,OverlayRuntime,SubsyncRuntime orchestration;
subgraph RuntimeServices["Runtime Domain Services"]
OverlayMgr["overlay-manager-service"]
OverlayWindow["overlay-window-service"]
OverlayVisibility["overlay-visibility-service"]
Ipc["ipc-service\nipc-command-service"]
RuntimeOpts["runtime-options-ipc-service"]
Mpv["mpv-service\nmpv-control-service"]
MpvTransport["mpv-transport\nmpv-protocol"]
Subtitle["subtitle-ws-service\nsecondary-subtitle-service"]
Shortcuts["shortcut-service\noverlay-shortcut-service"]
subgraph External["External Boundaries"]
Config["Config & CLI"]:::ext
Trackers["Window Trackers"]:::ext
Integrations["Jimaku & Subsync"]:::ext
end
class OverlayMgr,OverlayWindow,OverlayVisibility,Ipc,RuntimeOpts,Mpv,MpvTransport,Subtitle,Shortcuts domain;
subgraph Adapters["External Boundaries"]
Config["src/config/*"]
Cli["src/cli/*"]
Trackers["src/window-trackers/*"]
Integrations["src/jimaku/*\nsrc/subsync/*"]
end
class Config,Cli,Trackers,Integrations boundary;
Main --> Startup
Main --> IpcCli
Main --> Overlay
Main --> Subsync
Main -->|delegates to| Startup
Main -->|registers| AppLifecycle
AppLifecycle -->|triggers| StartupLifecycle
StartupLifecycle -->|initializes| State
Startup --> OverlaySvc
IpcCli --> ShortcutIpc
Overlay --> OverlaySvc
Overlay --> MpvSvc
Subsync --> Integrations
Main -->|builds deps| IpcRuntime
Main -->|builds deps| CliRuntime
Main -->|builds deps| OverlayRuntime
Main -->|builds deps| SubsyncRuntime
OverlaySvc --> Trackers
MpvSvc --> MiningSvc
ShortcutIpc --> Config
IpcRuntime -->|registers| Ipc
IpcRuntime -->|registers| RuntimeOpts
CliRuntime -->|registers| Cli
OverlayRuntime -->|manages| OverlayMgr
OverlayRuntime -->|manages| OverlayWindow
OverlayRuntime -->|manages| OverlayVisibility
Main -->|loads| Config
Ipc -->|updates| RuntimeOpts
Mpv -->|feeds| Subtitle
Shortcuts -->|drives| OverlayMgr
style Composition fill:#363a4f,stroke:#494d64,color:#cad3f5
style Services fill:#363a4f,stroke:#494d64,color:#cad3f5
style External fill:#363a4f,stroke:#494d64,color:#cad3f5
```
## Composition Pattern
@@ -189,35 +169,28 @@ This keeps side effects explicit and makes behavior easy to unit-test with fakes
```mermaid
flowchart TD
classDef phase fill:#494d64,stroke:#b7bdf8,color:#cad3f5,stroke-width:2px;
classDef decision fill:#494d64,stroke:#f5a97f,color:#cad3f5,stroke-width:2px;
classDef runtime fill:#494d64,stroke:#8aadf4,color:#cad3f5,stroke-width:2px;
classDef shutdown fill:#494d64,stroke:#a6da95,color:#cad3f5,stroke-width:2px;
classDef phase fill:#b7bdf8,stroke:#24273a,color:#24273a,stroke-width:1.5px
classDef decision fill:#f5a97f,stroke:#24273a,color:#24273a,stroke-width:1.5px
classDef runtime fill:#8aadf4,stroke:#24273a,color:#24273a,stroke-width:1.5px
classDef shutdown fill:#a6da95,stroke:#24273a,color:#24273a,stroke-width:1.5px
Args["CLI args / env"] --> Startup["src/main/startup.ts\nstartup-service"]
class Args,Startup phase;
Args["CLI args / env"]:::phase --> Startup["src/main/startup.ts"]:::phase
Startup --> Decision{"generate-config?"}
class Decision decision;
Startup --> Decision{"generate-config?"}:::decision
Decision -->|yes| WriteConfig["write config + exit"]
Decision -->|no| AppLifecycle["src/main/app-lifecycle.ts\napp-lifecycle-service"]
class WriteConfig,AppLifecycle phase;
Decision -->|yes| WriteConfig["Write config + exit"]:::phase
Decision -->|no| AppLifecycle["src/main/app-lifecycle.ts"]:::phase
AppLifecycle --> Ready["src/main/startup-lifecycle.ts\napp-ready flow\n(config + websocket policy + tracker/tokenizer init + state init)"]
class Ready phase;
AppLifecycle --> Ready["src/main/startup-lifecycle.ts\nConfig · WebSocket · Tracker · Tokenizer · State"]:::phase
Ready --> Runtime["src/main/* runtime modules:\nipc-runtime, cli-runtime, overlay-runtime, subsync-runtime"]
class Runtime runtime;
Ready --> Runtime["Runtime Modules\nipc · cli · overlay · subsync"]:::runtime
Runtime --> Overlay["overlay visibility + mining actions"]
Runtime --> Subtitle["subtitle + secondary-subtitle processing"]
Runtime --> Subsync["subsync / jimaku integration actions"]
class Overlay,Subtitle,Subsync runtime;
Runtime --> Overlay["Overlay & Mining"]:::runtime
Runtime --> Subtitle["Subtitle Processing"]:::runtime
Runtime --> SubsyncInt["Subsync & Jimaku"]:::runtime
Runtime --> WillQuit["Electron will-quit"]
WillQuit --> Cleanup["service-level teardown\n(unregister hooks, close resources)"]
class WillQuit,Cleanup shutdown;
Runtime --> WillQuit["Electron will-quit"]:::shutdown
WillQuit --> Cleanup["Service Teardown"]:::shutdown
```
## Why This Design

View File

@@ -2,6 +2,26 @@
Settings are stored in `$XDG_CONFIG_HOME/SubMiner/config.jsonc` (or `~/.config/SubMiner/config.jsonc` when `XDG_CONFIG_HOME` is unset). For backward compatibility, SubMiner also reads existing configs from lowercase `subminer` directories.
## Quick Start
For most users, start with this minimal configuration:
```json
{
"ankiConnect": {
"enabled": true,
"deck": "YourDeckName",
"fields": {
"sentence": "Sentence",
"audio": "Audio",
"image": "Image"
}
}
}
```
Then customize as needed using the sections below.
## Configuration File
See [config.example.jsonc](/config.example.jsonc) for a comprehensive example configuration file with all available options, default values, and detailed comments. Only include the options you want to customize in your config file.
@@ -196,12 +216,8 @@ To refresh roughly once per day, set:
}
```
<video controls playsinline preload="metadata" poster="/assets/kiku-integration-poster.jpg" style="width: 100%; max-width: 960px;">
<source :src="'/assets/kiku-integration.webm'" type="video/webm" />
Your browser does not support the video tag.
</video>
### Field Grouping Modes
<a :href="'/assets/kiku-integration.webm'" target="_blank" rel="noreferrer">Open demo in a new tab</a>
| Mode | Behavior |
| ---------- | -------------------------------------------------------------------------------------------------------------------------- |
| `auto` | Automatically merges the new card's content into the original; duplicate deletion is controlled by `deleteDuplicateInAuto` |
@@ -210,15 +226,22 @@ To refresh roughly once per day, set:
`deleteDuplicateInAuto` controls whether `auto` mode deletes the duplicate after merge (default: `true`). In `manual` mode, the popup asks each time whether to delete the duplicate.
<video controls playsinline preload="metadata" poster="/assets/kiku-integration-poster.jpg" style="width: 100%; max-width: 960px;">
<source :src="'/assets/kiku-integration.webm'" type="video/webm" />
Your browser does not support the video tag.
</video>
<a :href="'/assets/kiku-integration.webm'" target="_blank" rel="noreferrer">Open demo in a new tab</a>
**Image Quality Notes:**
- `imageQuality` affects JPG and WebP only; PNG is lossless and ignores this setting
- JPG quality is mapped to FFmpeg's scale (2-31, lower = better)
- WebP quality uses FFmpeg's native 0-100 scale
**Manual Card Update:**
### Manual Card Update Shortcuts
When `behavior.autoUpdateNewCards` is set to `false`, new cards are detected but not automatically updated. Instead, you can manually update cards using keyboard shortcuts:
When `behavior.autoUpdateNewCards` is set to `false`, new cards are detected but not automatically updated. Use these keyboard shortcuts for manual control:
| Shortcut | Action |
| -------------- | ------------------------------------------------------------------------------------------------------------ |
@@ -232,14 +255,14 @@ When `behavior.autoUpdateNewCards` is set to `false`, new cards are detected but
| `Ctrl+Shift+A` | Mark the last added Anki card as an audio card (sets IsAudioCard, SentenceAudio, Sentence, Picture) |
| `Ctrl+Shift+O` | Open runtime options palette (session-only live toggles) |
To copy multiple lines (current + previous):
**Multi-line copy workflow:**
1. Press `Ctrl+Shift+C`
2. Press a number key (`1-9`) within 3 seconds
3. The specified number of most recent subtitle lines are copied
4. Press `Ctrl+V` to update the last added card with the copied lines
These shortcuts are only active when the overlay window is visible. They are automatically disabled when the overlay is hidden to avoid interfering with normal system clipboard operations.
These shortcuts are only active when the overlay window is visible and automatically disabled when hidden.
### Auto-Start Overlay

View File

@@ -23,22 +23,44 @@ hero:
link: /configuration
features:
- icon: "🎯"
title: Click-to-Lookup Overlay
details: Subtitles are tokenized into clickable words. Click any word to open a Yomitan dictionary popup — right on top of the video.
- icon: "📇"
title: Automatic Anki Cards
details: Add a word from Yomitan and SubMiner fills in the sentence, audio clip, screenshot, and translation automatically.
- icon: "🪟"
- icon:
src: /assets/mpv.svg
alt: mpv icon
title: Built for mpv
details: Connects directly to mpv over IPC — tracks subtitles in real time, observes playback properties, and renders a self-contained overlay with everything bundled in a single application.
- icon:
src: /assets/yomitan-icon.svg
alt: Yomitan logo
title: Yomitan Integration
details: Hover over any word in the subtitles to trigger Yomitan dictionary lookups — get instant definitions without leaving the video player.
- icon:
src: /assets/anki-card.svg
alt: Anki card icon
title: Anki Card Enrichment
details: Add a word from Yomitan and SubMiner automatically updates the card with the sentence, audio clip, screenshot, and translation — no extra steps needed.
- icon:
src: /assets/dual-layer.svg
alt: Dual layer icon
title: Dual-Layer Subtitle System
details: Visible overlay with styled, interactive subtitles — plus an invisible layer that aligns with mpv's own subtitle rendering for seamless click-through lookup.
- icon: "🎬"
title: YouTube & Subtitle Sync
details: Play YouTube videos with auto-generated subtitles. Sync external subtitle files with alass or ffsubsync. Search and download anime subtitles from Jimaku.
- icon: "🔠"
title: Smart Tokenization
details: Japanese text is segmented using Yomitan's internal parser with MeCab fallback, enabling accurate word boundary detection for dictionary lookups.
- icon: "⌨️"
- icon:
src: /assets/highlight.svg
alt: Highlight icon
title: N+1 Word Highlighting
details: Highlights words you already know from your Anki deck, making it easy to spot new vocabulary and identify true N+1 sentences during immersion.
- icon:
src: /assets/texthooker.svg
alt: Texthooker icon
title: Texthooker & WebSocket
details: Built-in texthooker page that receives subtitles over WebSocket — use it as a clipboard inserter for Yomitan or connect external tools for real-time subtitle streaming.
- icon:
src: /assets/subtitle-download.svg
alt: Subtitle download icon
title: Subtitle Download & Sync
details: Search and download Japanese subtitles from Jimaku, then sync them to the audio with alass or ffsubsync — all from within the player.
- icon:
src: /assets/keyboard.svg
alt: Keyboard icon
title: Keyboard-Driven Workflow
details: Mine sentences, copy subtitles, cycle display modes, and trigger field grouping — all from configurable keyboard shortcuts without touching the mouse.
---
@@ -136,7 +158,7 @@ SubMiner sits as a transparent overlay on top of mpv. Subtitles appear as intera
<div class="workflow-step">
<div class="step-number">02</div>
<div class="step-title">Look Up</div>
<div class="step-desc">Click any word in the subtitle overlay. Yomitan opens its dictionary popup instantly.</div>
<div class="step-desc">Hover over a word in the subtitle overlay and hold Shift to trigger a Yomitan dictionary lookup.</div>
</div>
<div class="workflow-step">
<div class="step-number">03</div>

View File

@@ -25,6 +25,7 @@ The visible overlay renders subtitles as tokenized, clickable word spans. Each w
- Right-click to pause/resume
- Right-click + drag to reposition subtitles
- Modal dialogs for Jimaku search, field grouping, subsync, and runtime options
- **N+1 highlighting** — known words from your Anki deck are visually highlighted
Toggle with `Alt+Shift+O` (global) or `y-t` (mpv plugin).
@@ -106,7 +107,7 @@ When a card is created, SubMiner uses the secondary subtitle text as the transla
## Field Grouping (Kiku)
If you mine the same word from different sentences, SubMiner can merge the cards instead of creating duplicates. This feature is designed for use with [Kiku](https://github.com/donkuri/Kiku) and similar note types that support grouped fields.
If you mine the same word from different sentences, SubMiner can merge the cards instead of creating duplicates. This feature is designed for use with [Kiku](https://github.com/youyoumu/kiku) and similar note types that support grouped fields.
### How It Works
@@ -151,3 +152,41 @@ If your subtitle file is out of sync with the audio, SubMiner can resynchronize
4. SubMiner runs the sync and reloads the corrected subtitle.
Install the sync tools separately — see [Troubleshooting](/troubleshooting#subtitle-sync-subsync) if the tools are not found.
## N+1 Word Highlighting
When enabled, SubMiner highlights words you already know in your Anki deck, making it easier to spot new (N+1) vocabulary during immersion.
### How It Works
1. SubMiner periodically syncs with Anki to build a local cache of known words (expressions/headwords from your configured decks)
2. As subtitles appear, known words are visually highlighted in the visible overlay
3. Unknown words remain unhighlighted — these are your potential mining targets
### Enabling N+1 Mode
```json
{
"ankiConnect": {
"nPlusOne": {
"highlightEnabled": true,
"refreshMinutes": 1440,
"matchMode": "headword",
"decks": ["Learning::Japanese"]
}
}
}
```
| Option | Description |
|--------|-------------|
| `highlightEnabled` | Turn on/off the highlighting feature |
| `refreshMinutes` | How often to refresh the known-word cache (default: 1440 = daily) |
| `matchMode` | `"headword"` (dictionary form) or `"surface"` (exact text match) |
| `decks` | Which Anki decks to consider "known" (empty = uses `ankiConnect.deck`) |
### Use Cases
- **Immersion tracking**: Quickly identify which sentences contain only known words vs. those with new vocabulary
- **Mining focus**: Target sentences with exactly one unknown word (true N+1)
- **Progress visualization**: See your growing vocabulary visually represented in real content

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

View File

@@ -0,0 +1,15 @@
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48" fill="none">
<defs>
<linearGradient id="ac" x1="6" y1="6" x2="36" y2="42" gradientUnits="userSpaceOnUse">
<stop stop-color="#34d399"/>
<stop offset="1" stop-color="#059669"/>
</linearGradient>
</defs>
<rect x="12" y="5" width="24" height="34" rx="3" fill="#059669" opacity="0.18"/>
<rect x="8" y="9" width="24" height="34" rx="3" fill="url(#ac)"/>
<rect x="13" y="18" width="14" height="2.5" rx="1.25" fill="white" opacity="0.85"/>
<rect x="13" y="24" width="10" height="2.5" rx="1.25" fill="white" opacity="0.4"/>
<rect x="13" y="30" width="12" height="2.5" rx="1.25" fill="white" opacity="0.4"/>
<path d="M39.5 8l1.8 4.2 4.2 1.8-4.2 1.8L39.5 20l-1.8-4.2L33.5 14l4.2-1.8z" fill="#34d399"/>
<path d="M36 27l1 2.3 2.3 1-2.3 1L36 33.5l-1-2.2-2.3-1 2.3-1z" fill="#34d399" opacity="0.45"/>
</svg>

After

Width:  |  Height:  |  Size: 914 B

View File

@@ -0,0 +1,15 @@
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48" fill="none">
<defs>
<linearGradient id="dl" x1="4" y1="24" x2="44" y2="24" gradientUnits="userSpaceOnUse">
<stop stop-color="#818cf8"/>
<stop offset="1" stop-color="#6366f1"/>
</linearGradient>
</defs>
<rect x="4" y="6" width="40" height="14" rx="4" fill="#818cf8" opacity="0.12"/>
<rect x="4" y="6" width="40" height="14" rx="4" stroke="#818cf8" stroke-width="1.5" stroke-dasharray="4 3" fill="none" opacity="0.55"/>
<rect x="10" y="11" width="20" height="3" rx="1.5" fill="#818cf8" opacity="0.35"/>
<line x1="24" y1="22" x2="24" y2="26" stroke="#a5b4fc" stroke-width="1.5" stroke-linecap="round" opacity="0.5"/>
<path d="M21.5 24.5L24 27l2.5-2.5" stroke="#a5b4fc" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" fill="none" opacity="0.5"/>
<rect x="4" y="28" width="40" height="14" rx="4" fill="url(#dl)"/>
<rect x="10" y="33" width="20" height="3" rx="1.5" fill="white" opacity="0.85"/>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@@ -0,0 +1,13 @@
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48" fill="none">
<defs>
<linearGradient id="hl" x1="20" y1="14" x2="38" y2="34" gradientUnits="userSpaceOnUse">
<stop stop-color="#fbbf24"/>
<stop offset="1" stop-color="#f59e0b"/>
</linearGradient>
</defs>
<rect x="2" y="17" width="10" height="14" rx="3" fill="#fbbf24" opacity="0.3"/>
<rect x="14" y="17" width="7" height="14" rx="3" fill="#fbbf24" opacity="0.3"/>
<rect x="23" y="13" width="13" height="22" rx="3.5" fill="url(#hl)"/>
<rect x="38" y="17" width="8" height="14" rx="3" fill="#fbbf24" opacity="0.3"/>
<path d="M28.2 4l1 2.4 2.4 1-2.4 1-1 2.4-1-2.4-2.4-1 2.4-1z" fill="#fbbf24" opacity="0.7"/>
</svg>

After

Width:  |  Height:  |  Size: 729 B

View File

@@ -0,0 +1,21 @@
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48" fill="none">
<defs>
<linearGradient id="kb" x1="2" y1="10" x2="46" y2="42" gradientUnits="userSpaceOnUse">
<stop stop-color="#c084fc"/>
<stop offset="1" stop-color="#7c3aed"/>
</linearGradient>
</defs>
<rect x="2" y="12" width="44" height="30" rx="5" fill="url(#kb)" opacity="0.12"/>
<rect x="2" y="12" width="44" height="30" rx="5" stroke="url(#kb)" stroke-width="1.5" fill="none"/>
<rect x="6" y="16" width="8" height="6" rx="2" fill="url(#kb)"/>
<rect x="16" y="16" width="8" height="6" rx="2" fill="url(#kb)" opacity="0.35"/>
<rect x="26" y="16" width="8" height="6" rx="2" fill="url(#kb)" opacity="0.35"/>
<rect x="36" y="16" width="8" height="6" rx="2" fill="url(#kb)" opacity="0.35"/>
<rect x="6" y="24" width="8" height="6" rx="2" fill="url(#kb)" opacity="0.35"/>
<rect x="16" y="24" width="8" height="6" rx="2" fill="url(#kb)" opacity="0.35"/>
<rect x="26" y="24" width="8" height="6" rx="2" fill="url(#kb)" opacity="0.35"/>
<rect x="36" y="24" width="8" height="6" rx="2" fill="url(#kb)"/>
<rect x="6" y="32" width="8" height="6" rx="2" fill="url(#kb)" opacity="0.35"/>
<rect x="16" y="32" width="16" height="6" rx="2" fill="url(#kb)" opacity="0.35"/>
<rect x="34" y="32" width="10" height="6" rx="2" fill="url(#kb)" opacity="0.35"/>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -0,0 +1,86 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="64"
height="64"
viewBox="0 0 63.999999 63.999999"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
sodipodi:docname="mpv.svg">
<defs
id="defs4" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="5.3710484"
inkscape:cx="10.112865"
inkscape:cy="18.643164"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:window-width="1920"
inkscape:window-height="1016"
inkscape:window-x="0"
inkscape:window-y="27"
inkscape:window-maximized="1" />
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-988.3622)">
<circle
style="opacity:1;fill:#e5e5e5;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.10161044;stroke-linecap:round;stroke-linejoin:bevel;stroke-miterlimit:1;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.99215686"
id="path4380"
cx="32"
cy="1020.3622"
r="27.949194" />
<circle
style="opacity:1;fill:#672168;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.0988237;stroke-linecap:round;stroke-linejoin:bevel;stroke-miterlimit:1;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.99215686"
id="path4390"
cx="32.727058"
cy="1019.5079"
r="25.950588" />
<circle
style="opacity:1;fill:#420143;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.1;stroke-linecap:round;stroke-linejoin:bevel;stroke-miterlimit:1;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.99215686"
id="path4400"
cx="34.224396"
cy="1017.7957"
r="20" />
<path
style="fill:#dddbdd;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 44.481446,1020.4807 a 12.848894,12.848894 0 0 1 -12.84889,12.8489 12.848894,12.848894 0 0 1 -12.8489,-12.8489 12.848894,12.848894 0 0 1 12.8489,-12.8489 12.848894,12.848894 0 0 1 12.84889,12.8489 z"
id="path4412"
inkscape:connector-curvature="0" />
<path
style="fill:#691f69;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 28.374316,1014.709 0,11.4502 9.21608,-5.8647 z"
id="path4426"
inkscape:connector-curvature="0" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

@@ -0,0 +1,16 @@
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48" fill="none">
<defs>
<linearGradient id="sd" x1="4" y1="4" x2="44" y2="44" gradientUnits="userSpaceOnUse">
<stop stop-color="#22d3ee"/>
<stop offset="1" stop-color="#0891b2"/>
</linearGradient>
</defs>
<rect x="8" y="4" width="24" height="32" rx="3" fill="url(#sd)" opacity="0.15"/>
<rect x="8" y="4" width="24" height="32" rx="3" stroke="url(#sd)" stroke-width="1.5" fill="none"/>
<rect x="13" y="12" width="14" height="2.5" rx="1.25" fill="#22d3ee" opacity="0.5"/>
<rect x="13" y="18" width="10" height="2.5" rx="1.25" fill="#22d3ee" opacity="0.35"/>
<rect x="13" y="24" width="12" height="2.5" rx="1.25" fill="#22d3ee" opacity="0.35"/>
<line x1="38" y1="16" x2="38" y2="32" stroke="url(#sd)" stroke-width="2.5" stroke-linecap="round"/>
<path d="M33 28l5 5 5-5" stroke="url(#sd)" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" fill="none"/>
<line x1="33" y1="40" x2="43" y2="40" stroke="url(#sd)" stroke-width="2" stroke-linecap="round" opacity="0.5"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1,19 @@
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48" fill="none">
<defs>
<linearGradient id="th" x1="4" y1="6" x2="44" y2="42" gradientUnits="userSpaceOnUse">
<stop stop-color="#f97316"/>
<stop offset="1" stop-color="#c2410c"/>
</linearGradient>
</defs>
<rect x="4" y="6" width="30" height="36" rx="4" fill="url(#th)" opacity="0.12"/>
<rect x="4" y="6" width="30" height="36" rx="4" stroke="url(#th)" stroke-width="1.5" fill="none"/>
<rect x="9" y="14" width="14" height="2.5" rx="1.25" fill="#f97316" opacity="0.6"/>
<rect x="9" y="20" width="18" height="2.5" rx="1.25" fill="#f97316" opacity="0.4"/>
<rect x="9" y="26" width="12" height="2.5" rx="1.25" fill="#f97316" opacity="0.4"/>
<rect x="9" y="32" width="16" height="2.5" rx="1.25" fill="#f97316" opacity="0.4"/>
<circle cx="40" cy="18" r="3.5" fill="url(#th)" opacity="0.8"/>
<circle cx="40" cy="30" r="3.5" fill="url(#th)" opacity="0.8"/>
<line x1="36" y1="18" x2="34" y2="18" stroke="url(#th)" stroke-width="1.5" stroke-linecap="round" opacity="0.6"/>
<line x1="36" y1="30" x2="34" y2="30" stroke="url(#th)" stroke-width="1.5" stroke-linecap="round" opacity="0.6"/>
<line x1="40" y1="21.5" x2="40" y2="26.5" stroke="url(#th)" stroke-width="1.5" stroke-linecap="round" opacity="0.5"/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -0,0 +1,16 @@
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48" fill="none">
<defs>
<linearGradient id="tk" x1="0" y1="14" x2="48" y2="34" gradientUnits="userSpaceOnUse">
<stop stop-color="#22d3ee"/>
<stop offset="1" stop-color="#0891b2"/>
</linearGradient>
</defs>
<rect x="2" y="12" width="12" height="24" rx="3.5" fill="url(#tk)"/>
<rect x="18" y="12" width="12" height="24" rx="3.5" fill="url(#tk)"/>
<rect x="34" y="12" width="12" height="24" rx="3.5" fill="url(#tk)"/>
<line x1="15.5" y1="10" x2="15.5" y2="38" stroke="#22d3ee" stroke-width="1.5" stroke-linecap="round" stroke-dasharray="3 3" opacity="0.45"/>
<line x1="32.5" y1="10" x2="32.5" y2="38" stroke="#22d3ee" stroke-width="1.5" stroke-linecap="round" stroke-dasharray="3 3" opacity="0.45"/>
<rect x="5" y="22" width="6" height="2.5" rx="1.25" fill="white" opacity="0.7"/>
<rect x="21" y="22" width="6" height="2.5" rx="1.25" fill="white" opacity="0.7"/>
<rect x="37" y="22" width="6" height="2.5" rx="1.25" fill="white" opacity="0.7"/>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@@ -0,0 +1,12 @@
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48" fill="none">
<defs>
<linearGradient id="vd" x1="4" y1="10" x2="44" y2="38" gradientUnits="userSpaceOnUse">
<stop stop-color="#fb7185"/>
<stop offset="1" stop-color="#e11d48"/>
</linearGradient>
</defs>
<rect x="4" y="10" width="40" height="28" rx="4" fill="url(#vd)" opacity="0.15"/>
<rect x="4" y="10" width="40" height="28" rx="4" stroke="url(#vd)" stroke-width="1.5" fill="none"/>
<path d="M20 18l12 6-12 6z" fill="url(#vd)"/>
<rect x="10" y="32" width="22" height="2.5" rx="1.25" fill="white" opacity="0.4"/>
</svg>

After

Width:  |  Height:  |  Size: 635 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><defs><linearGradient id="a" x1="11.876" x2="4.014" y1="4.073" y2="11.935" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#bc00ff" stop-opacity=".941" style="stop-color:#bc00ff;stop-opacity:1"/><stop offset="1" stop-color="#00b9fe"/></linearGradient></defs><rect width="16" height="16" fill="url(#a)" rx="1.625" ry="1.625"/><path d="M2 2v2h3v3H2v2h3v3H2v2h5V2Zm7 0v2h5V2Zm0 5v2h5V7Zm0 5v2h5v-2z" shape-rendering="crispEdges" style="fill:#fff"/></svg>

After

Width:  |  Height:  |  Size: 527 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
docs/public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB