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', title: 'SubMiner Docs',
description: 'All-in-one sentence mining overlay for MPV with AnkiConnect and dictionary integration', description: 'All-in-one sentence mining overlay for MPV with AnkiConnect and dictionary integration',
base, 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', appearance: 'dark',
cleanUrls: true, cleanUrls: true,
lastUpdated: 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) ## 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 ```jsonc
"ankiConnect": { "ankiConnect": {

View File

@@ -86,71 +86,51 @@ src/renderer/
```mermaid ```mermaid
flowchart TD flowchart TD
classDef root fill:#c6a0f6,stroke:#181926,color:#181926,stroke-width:2px; classDef root fill:#c6a0f6,stroke:#24273a,color:#24273a,stroke-width:2px
classDef orchestration fill:#494d64,stroke:#b7bdf8,color:#cad3f5,stroke-width:2px; classDef comp fill:#b7bdf8,stroke:#24273a,color:#24273a,stroke-width:1.5px
classDef domain fill:#494d64,stroke:#8aadf4,color:#cad3f5,stroke-width:2px; classDef svc fill:#8aadf4,stroke:#24273a,color:#24273a,stroke-width:1.5px
classDef boundary fill:#494d64,stroke:#a6da95,color:#cad3f5,stroke-width:2px; classDef ext fill:#a6da95,stroke:#24273a,color:#24273a,stroke-width:1.5px
subgraph Entry["Entrypoint"] Main["src/main.ts"]:::root
Main["src/main.ts\nentry point"]
subgraph Composition["Composition Modules"]
Startup["Startup & Lifecycle"]:::comp
IpcCli["IPC & CLI Wiring"]:::comp
Overlay["Overlay & Shortcuts"]:::comp
Subsync["Subsync"]:::comp
end end
class Main root;
subgraph MainModules["src/main/ Composition Modules"] subgraph Services["Domain Services"]
Startup["startup.ts\nbootstrap flow"] OverlaySvc["Overlay Services"]:::svc
AppLifecycle["app-lifecycle.ts\nlifecycle events"] MpvSvc["MPV Stack"]:::svc
StartupLifecycle["startup-lifecycle.ts\napp-ready sequence"] MiningSvc["Mining & Subtitles"]:::svc
State["state.ts\nruntime state container"] ShortcutIpc["Shortcuts & IPC"]:::svc
IpcRuntime["ipc-runtime.ts\nIPC handlers"]
CliRuntime["cli-runtime.ts\nCLI dispatch"]
OverlayRuntime["overlay-runtime.ts\nwindow/modal"]
SubsyncRuntime["subsync-runtime.ts\nsubsync orchestration"]
end end
class Startup,AppLifecycle,StartupLifecycle,State,IpcRuntime,CliRuntime,OverlayRuntime,SubsyncRuntime orchestration;
subgraph RuntimeServices["Runtime Domain Services"] subgraph External["External Boundaries"]
OverlayMgr["overlay-manager-service"] Config["Config & CLI"]:::ext
OverlayWindow["overlay-window-service"] Trackers["Window Trackers"]:::ext
OverlayVisibility["overlay-visibility-service"] Integrations["Jimaku & Subsync"]:::ext
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"]
end end
class OverlayMgr,OverlayWindow,OverlayVisibility,Ipc,RuntimeOpts,Mpv,MpvTransport,Subtitle,Shortcuts domain;
subgraph Adapters["External Boundaries"] Main --> Startup
Config["src/config/*"] Main --> IpcCli
Cli["src/cli/*"] Main --> Overlay
Trackers["src/window-trackers/*"] Main --> Subsync
Integrations["src/jimaku/*\nsrc/subsync/*"]
end
class Config,Cli,Trackers,Integrations boundary;
Main -->|delegates to| Startup Startup --> OverlaySvc
Main -->|registers| AppLifecycle IpcCli --> ShortcutIpc
AppLifecycle -->|triggers| StartupLifecycle Overlay --> OverlaySvc
StartupLifecycle -->|initializes| State Overlay --> MpvSvc
Subsync --> Integrations
Main -->|builds deps| IpcRuntime OverlaySvc --> Trackers
Main -->|builds deps| CliRuntime MpvSvc --> MiningSvc
Main -->|builds deps| OverlayRuntime ShortcutIpc --> Config
Main -->|builds deps| SubsyncRuntime
IpcRuntime -->|registers| Ipc style Composition fill:#363a4f,stroke:#494d64,color:#cad3f5
IpcRuntime -->|registers| RuntimeOpts style Services fill:#363a4f,stroke:#494d64,color:#cad3f5
CliRuntime -->|registers| Cli style External fill:#363a4f,stroke:#494d64,color:#cad3f5
OverlayRuntime -->|manages| OverlayMgr
OverlayRuntime -->|manages| OverlayWindow
OverlayRuntime -->|manages| OverlayVisibility
Main -->|loads| Config
Ipc -->|updates| RuntimeOpts
Mpv -->|feeds| Subtitle
Shortcuts -->|drives| OverlayMgr
``` ```
## Composition Pattern ## Composition Pattern
@@ -189,35 +169,28 @@ This keeps side effects explicit and makes behavior easy to unit-test with fakes
```mermaid ```mermaid
flowchart TD flowchart TD
classDef phase fill:#494d64,stroke:#b7bdf8,color:#cad3f5,stroke-width:2px; classDef phase fill:#b7bdf8,stroke:#24273a,color:#24273a,stroke-width:1.5px
classDef decision fill:#494d64,stroke:#f5a97f,color:#cad3f5,stroke-width:2px; classDef decision fill:#f5a97f,stroke:#24273a,color:#24273a,stroke-width:1.5px
classDef runtime fill:#494d64,stroke:#8aadf4,color:#cad3f5,stroke-width:2px; classDef runtime fill:#8aadf4,stroke:#24273a,color:#24273a,stroke-width:1.5px
classDef shutdown fill:#494d64,stroke:#a6da95,color:#cad3f5,stroke-width:2px; classDef shutdown fill:#a6da95,stroke:#24273a,color:#24273a,stroke-width:1.5px
Args["CLI args / env"] --> Startup["src/main/startup.ts\nstartup-service"] Args["CLI args / env"]:::phase --> Startup["src/main/startup.ts"]:::phase
class Args,Startup phase;
Startup --> Decision{"generate-config?"} Startup --> Decision{"generate-config?"}:::decision
class Decision decision;
Decision -->|yes| WriteConfig["write config + exit"] Decision -->|yes| WriteConfig["Write config + exit"]:::phase
Decision -->|no| AppLifecycle["src/main/app-lifecycle.ts\napp-lifecycle-service"] Decision -->|no| AppLifecycle["src/main/app-lifecycle.ts"]:::phase
class WriteConfig,AppLifecycle phase;
AppLifecycle --> Ready["src/main/startup-lifecycle.ts\napp-ready flow\n(config + websocket policy + tracker/tokenizer init + state init)"] AppLifecycle --> Ready["src/main/startup-lifecycle.ts\nConfig · WebSocket · Tracker · Tokenizer · State"]:::phase
class Ready phase;
Ready --> Runtime["src/main/* runtime modules:\nipc-runtime, cli-runtime, overlay-runtime, subsync-runtime"] Ready --> Runtime["Runtime Modules\nipc · cli · overlay · subsync"]:::runtime
class Runtime runtime;
Runtime --> Overlay["overlay visibility + mining actions"] Runtime --> Overlay["Overlay & Mining"]:::runtime
Runtime --> Subtitle["subtitle + secondary-subtitle processing"] Runtime --> Subtitle["Subtitle Processing"]:::runtime
Runtime --> Subsync["subsync / jimaku integration actions"] Runtime --> SubsyncInt["Subsync & Jimaku"]:::runtime
class Overlay,Subtitle,Subsync runtime;
Runtime --> WillQuit["Electron will-quit"] Runtime --> WillQuit["Electron will-quit"]:::shutdown
WillQuit --> Cleanup["service-level teardown\n(unregister hooks, close resources)"] WillQuit --> Cleanup["Service Teardown"]:::shutdown
class WillQuit,Cleanup shutdown;
``` ```
## Why This Design ## 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. 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 ## 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. 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;"> ### Field Grouping Modes
<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>
| Mode | Behavior | | Mode | Behavior |
| ---------- | -------------------------------------------------------------------------------------------------------------------------- | | ---------- | -------------------------------------------------------------------------------------------------------------------------- |
| `auto` | Automatically merges the new card's content into the original; duplicate deletion is controlled by `deleteDuplicateInAuto` | | `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. `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:** **Image Quality Notes:**
- `imageQuality` affects JPG and WebP only; PNG is lossless and ignores this setting - `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) - JPG quality is mapped to FFmpeg's scale (2-31, lower = better)
- WebP quality uses FFmpeg's native 0-100 scale - 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 | | 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+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) | | `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` 1. Press `Ctrl+Shift+C`
2. Press a number key (`1-9`) within 3 seconds 2. Press a number key (`1-9`) within 3 seconds
3. The specified number of most recent subtitle lines are copied 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 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 ### Auto-Start Overlay

View File

@@ -23,22 +23,44 @@ hero:
link: /configuration link: /configuration
features: features:
- icon: "🎯" - icon:
title: Click-to-Lookup Overlay src: /assets/mpv.svg
details: Subtitles are tokenized into clickable words. Click any word to open a Yomitan dictionary popup — right on top of the video. alt: mpv icon
- icon: "📇" title: Built for mpv
title: Automatic Anki Cards 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.
details: Add a word from Yomitan and SubMiner fills in the sentence, audio clip, screenshot, and translation automatically. - icon:
- 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 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. 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: "🎬" - icon:
title: YouTube & Subtitle Sync src: /assets/highlight.svg
details: Play YouTube videos with auto-generated subtitles. Sync external subtitle files with alass or ffsubsync. Search and download anime subtitles from Jimaku. alt: Highlight icon
- icon: "🔠" title: N+1 Word Highlighting
title: Smart Tokenization 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.
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/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 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. 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="workflow-step">
<div class="step-number">02</div> <div class="step-number">02</div>
<div class="step-title">Look Up</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>
<div class="workflow-step"> <div class="workflow-step">
<div class="step-number">03</div> <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 to pause/resume
- Right-click + drag to reposition subtitles - Right-click + drag to reposition subtitles
- Modal dialogs for Jimaku search, field grouping, subsync, and runtime options - 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). 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) ## 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 ### 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. 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. 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