New:Socket for Asana Is Now Available.Learn more
Get Started

Yunit – companion language layer

Package Overview
Versions
2
Alerts
File Explorer
Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

yunit@yunit.app - firefox Package Compare versions

Comparing version
0.2.0
to
0.2.2
+1
-1
manifest.json
{
"manifest_version": 3,
"name": "Yunit \u2013 companion language layer",
"version": "0.2.0",
"version": "0.2.2",
"description": "Picks words from any page you read and quietly translates a few of them, so vocabulary travels with you.",

@@ -6,0 +6,0 @@ "permissions": [

@@ -9,3 +9,9 @@ (() => {

// "lemma migration done" flag. Kept indefinitely as a safety net.
preLemmaSnapshot: "yunit.vocab.preLemma"
preLemmaSnapshot: "yunit.vocab.preLemma",
// Per-video lyrics state, both LRU-capped maps keyed by YT video id.
// Nudges: the manual sync offset the user dialed in, so a rewatch
// doesn't make them re-tune. Cache: the resolved LRCLIB payload, so a
// rewatch renders instantly without re-hitting the API.
lyricsNudges: "yunit.lyrics.nudges",
lyricsCache: "yunit.lyrics.cache"
};

@@ -167,3 +173,18 @@ var extDead = false;

// default surface rather than an Alt+Shift+L away.
lyricsAutoOpen: false
lyricsAutoOpen: false,
// On-video karaoke overlay appearance. Style picks the contrast strategy
// against the footage: 'shadow' (soft dark halo, the original), 'outline'
// (hard stroke, holds up on mid-brightness video), 'plate' (caption-style
// scrim behind the text — readable on anything). Color is a small curated
// palette of light inks; size multiplies the player-width-derived base
// font. nextLine shows the upcoming lyric dimmed under the current one.
// Controls live in the lyrics panel header, not the popup — appearance
// is tuned while watching.
lyricsOverlayStyle: "shadow",
// 'shadow' | 'outline' | 'plate'
lyricsOverlayColor: "white",
// 'white' | 'cream' | 'yellow' | 'cyan'
lyricsOverlaySize: "medium",
// 'small' | 'medium' | 'large'
lyricsOverlayNextLine: false
};

@@ -170,0 +191,0 @@ var settings = { ...DEFAULTS };

+243
-15

@@ -854,2 +854,4 @@ /* Yunit — companion language layer

gap: 6px;
/* Anchors the appearance menu's absolute positioning. */
position: relative;
}

@@ -888,3 +890,4 @@ .yunit-lyrics-header-row {

.yunit-lyrics-follow,
.yunit-lyrics-overlay {
.yunit-lyrics-overlay,
.yunit-lyrics-appearance {
flex-shrink: 0;

@@ -907,6 +910,8 @@ background: transparent;

.yunit-lyrics-follow[hidden],
.yunit-lyrics-overlay[hidden] { display: none; }
.yunit-lyrics-overlay[hidden],
.yunit-lyrics-appearance[hidden] { display: none; }
.yunit-lyrics-gloss:hover,
.yunit-lyrics-follow:hover,
.yunit-lyrics-overlay:hover {
.yunit-lyrics-overlay:hover,
.yunit-lyrics-appearance:hover {
border-color: hsla(355, 45%, 32%, 0.45);

@@ -918,3 +923,4 @@ color: hsl(355, 45%, 32%);

.yunit-lyrics-follow[data-on="true"],
.yunit-lyrics-overlay[data-on="true"] {
.yunit-lyrics-overlay[data-on="true"],
.yunit-lyrics-appearance[aria-expanded="true"] {
color: hsl(355, 50%, 26%);

@@ -924,2 +930,76 @@ background: hsla(355, 45%, 32%, 0.08);

}
/* Appearance menu — a small settings card hanging off the header's action
row. Same paper-and-ink register as the rest of the panel. */
.yunit-lyrics-appearance-menu {
position: absolute;
top: 100%;
right: 12px;
z-index: 40;
min-width: 230px;
background: hsl(40, 35%, 97%);
border: 1px solid hsl(28, 18%, 84%);
border-radius: 8px;
box-shadow: 0 6px 20px hsla(28, 30%, 15%, 0.14);
padding: 10px 12px;
display: flex;
flex-direction: column;
gap: 9px;
}
.yunit-lyrics-appearance-menu[hidden] { display: none; }
.yunit-lyrics-appearance-row {
display: flex;
align-items: center;
justify-content: space-between;
gap: 10px;
}
.yunit-lyrics-appearance-label {
font-size: 11px;
font-weight: 600;
letter-spacing: 0.3px;
text-transform: uppercase;
color: hsl(28, 10%, 50%);
white-space: nowrap;
}
.yunit-lyrics-appearance-options {
display: inline-flex;
gap: 4px;
}
.yunit-lyrics-appearance-options button {
background: transparent;
border: 1px solid hsl(28, 18%, 82%);
border-radius: 5px;
font-family: inherit;
font-size: 11px;
color: hsl(28, 10%, 42%);
cursor: pointer;
padding: 0 7px;
height: 22px;
line-height: 20px;
transition: background 0.12s ease, color 0.12s ease, border-color 0.12s ease;
}
.yunit-lyrics-appearance-options button:hover {
border-color: hsla(355, 45%, 32%, 0.45);
color: hsl(355, 45%, 32%);
}
.yunit-lyrics-appearance-options button[data-active="true"],
.yunit-lyrics-appearance-options button[data-on="true"] {
color: hsl(355, 50%, 26%);
background: hsla(355, 45%, 32%, 0.08);
border-color: hsla(355, 45%, 32%, 0.4);
}
/* Color swatches — the ink itself is the label (set inline from JS).
A subtle dark inlay keeps the white swatch visible on cream paper. */
.yunit-lyrics-appearance-swatches button {
width: 22px;
min-width: 22px;
padding: 0;
border-radius: 50%;
box-shadow: inset 0 0 0 1px hsla(28, 30%, 20%, 0.18);
}
.yunit-lyrics-appearance-swatches button[data-active="true"] {
border-color: hsl(355, 45%, 32%);
box-shadow: inset 0 0 0 1px hsla(28, 30%, 20%, 0.18),
0 0 0 2px hsla(355, 45%, 32%, 0.25);
}
.yunit-lyrics-gloss[data-mode="off"],

@@ -1115,2 +1195,11 @@ .yunit-lyrics-follow[data-on="false"] { color: hsl(28, 10%, 60%); }

/* On-video overlay. Appearance is driven by custom properties + data
attributes set from lyrics.js:
--yunit-lyrics-base px size derived from the player's width
--yunit-lyrics-scale the user's S/M/L multiplier
--yunit-lyrics-color / --yunit-lyrics-color-dim chosen ink
data-style contrast strategy: shadow | outline | plate
data-next upcoming-line preview: on | off
The lifted class moves us above YouTube's own caption band when both
are showing. */
.yunit-video-overlay {

@@ -1126,9 +1215,10 @@ position: absolute;

opacity: 0;
transition: opacity 0.3s ease;
transition: opacity 0.3s ease, bottom 0.25s ease;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
}
.yunit-video-overlay.yunit-video-overlay-on { opacity: 1; }
.yunit-video-overlay.yunit-video-overlay-lifted { bottom: 170px; }
.yunit-video-source,
.yunit-video-target {
text-shadow: 0 0 6px rgba(0, 0, 0, 0.95), 0 2px 6px rgba(0, 0, 0, 0.7);
.yunit-video-target,
.yunit-video-next {
line-height: 1.3;

@@ -1139,14 +1229,62 @@ word-wrap: break-word;

.yunit-video-source {
font-size: 24px;
font-size: calc(var(--yunit-lyrics-base, 24px) * var(--yunit-lyrics-scale, 1));
font-weight: 500;
color: white;
color: var(--yunit-lyrics-color, #ffffff);
margin-bottom: 4px;
}
.yunit-video-target {
font-size: 18px;
color: rgba(255, 255, 255, 0.85);
font-size: calc(var(--yunit-lyrics-base, 24px) * var(--yunit-lyrics-scale, 1) * 0.75);
color: var(--yunit-lyrics-color-dim, rgba(255, 255, 255, 0.85));
font-style: italic;
}
.yunit-video-next {
font-size: calc(var(--yunit-lyrics-base, 24px) * var(--yunit-lyrics-scale, 1) * 0.7);
color: var(--yunit-lyrics-color-dim, rgba(255, 255, 255, 0.85));
opacity: 0.55;
margin-top: 6px;
}
.yunit-video-overlay:not([data-next="on"]) .yunit-video-next { display: none; }
.yunit-video-source:empty,
.yunit-video-target:empty { display: none; }
.yunit-video-target:empty,
.yunit-video-next:empty { display: none; }
/* Contrast strategies. Shadow is the default (also applies when the
data-style attribute is absent for any reason). Offsets are in em so
the halo / stroke scales with the font. */
.yunit-video-overlay:not([data-style="outline"]):not([data-style="plate"]) .yunit-video-source,
.yunit-video-overlay:not([data-style="outline"]):not([data-style="plate"]) .yunit-video-target,
.yunit-video-overlay:not([data-style="outline"]):not([data-style="plate"]) .yunit-video-next {
text-shadow: 0 0 0.25em rgba(0, 0, 0, 0.95), 0 0.08em 0.25em rgba(0, 0, 0, 0.7);
}
/* Outline — a hard dark stroke built from layered shadows; survives
mid-brightness footage where a soft halo washes out. */
.yunit-video-overlay[data-style="outline"] .yunit-video-source,
.yunit-video-overlay[data-style="outline"] .yunit-video-target,
.yunit-video-overlay[data-style="outline"] .yunit-video-next {
text-shadow:
-0.045em -0.045em 0 rgba(0, 0, 0, 0.9),
0.045em -0.045em 0 rgba(0, 0, 0, 0.9),
-0.045em 0.045em 0 rgba(0, 0, 0, 0.9),
0.045em 0.045em 0 rgba(0, 0, 0, 0.9),
0 -0.06em 0 rgba(0, 0, 0, 0.9),
0 0.06em 0 rgba(0, 0, 0, 0.9),
-0.06em 0 0 rgba(0, 0, 0, 0.9),
0.06em 0 0 rgba(0, 0, 0, 0.9),
0 0.1em 0.3em rgba(0, 0, 0, 0.45);
}
/* Plate — a caption-style scrim behind each line. Reads on any footage,
including white-on-white concert lighting. */
.yunit-video-overlay[data-style="plate"] .yunit-video-source,
.yunit-video-overlay[data-style="plate"] .yunit-video-target,
.yunit-video-overlay[data-style="plate"] .yunit-video-next {
background: rgba(0, 0, 0, 0.62);
width: fit-content;
max-width: min(88%, 920px);
margin-left: auto;
margin-right: auto;
padding: 0.08em 0.55em 0.16em;
border-radius: 0.28em;
}
.yunit-video-overlay[data-style="plate"] .yunit-video-source { margin-bottom: 0.18em; }
.yunit-video-overlay[data-style="plate"] .yunit-video-next { margin-top: 0.3em; }
.yunit-lyrics-meta { flex: 1; min-width: 0; }

@@ -1237,2 +1375,7 @@ .yunit-lyrics-title {

border-radius: 5px;
/* Lyric lines are content, not chrome — same editorial serif as the
panel title and the dual-view glosses, so the panel reads as a page
from the commonplace book rather than a widget. */
font-family: 'Iowan Old Style', 'Charter', 'Cambria', Georgia, serif;
font-size: 15px;
color: hsl(28, 10%, 42%);

@@ -1243,2 +1386,8 @@ transition: background 0.4s ease, color 0.3s ease;

}
/* Synced lyrics are seekable — click a line to replay it. The affordance
is a quiet brand-tint hover; the active line keeps its live purple. */
.yunit-lyrics-body[data-synced="true"] .yunit-lyrics-line { cursor: pointer; }
.yunit-lyrics-body[data-synced="true"] .yunit-lyrics-line:hover:not(.yunit-lyrics-active) {
background: hsla(355, 45%, 32%, 0.05);
}
/* Active line during synced playback — uses the "live" purple, distinct

@@ -1518,3 +1667,5 @@ from the burgundy brand accent so the user reads it as a transient

html[dark] .yunit-lyrics-follow,
html[dark] .yunit-lyrics-overlay {
html[dark] .yunit-lyrics-overlay,
html[dark] .yunit-lyrics-appearance,
html[dark] .yunit-lyrics-search-other {
border-color: #4a4550;

@@ -1527,3 +1678,5 @@ color: #a89f8d;

html[dark] .yunit-lyrics-follow:hover,
html[dark] .yunit-lyrics-overlay:hover {
html[dark] .yunit-lyrics-overlay:hover,
html[dark] .yunit-lyrics-appearance:hover,
html[dark] .yunit-lyrics-search-other:hover {
color: hsl(355, 60%, 82%);

@@ -1535,3 +1688,4 @@ border-color: hsla(355, 50%, 60%, 0.5);

html[dark] .yunit-lyrics-follow[data-on="true"],
html[dark] .yunit-lyrics-overlay[data-on="true"] {
html[dark] .yunit-lyrics-overlay[data-on="true"],
html[dark] .yunit-lyrics-appearance[aria-expanded="true"] {
color: hsl(355, 60%, 84%);

@@ -1541,2 +1695,76 @@ background: hsla(355, 45%, 50%, 0.18);

}
html[dark] .yunit-lyrics-body[data-synced="true"] .yunit-lyrics-line:hover:not(.yunit-lyrics-active) {
background: hsla(355, 45%, 70%, 0.08);
}
html[dark] .yunit-lyrics-sharpen {
border-color: #4a4550;
color: #ddd9d2;
}
html[dark] .yunit-lyrics-sharpen:hover:not([disabled]) {
color: hsl(355, 60%, 84%);
border-color: hsla(355, 50%, 60%, 0.5);
background: hsla(355, 45%, 50%, 0.18);
}
html[dark] .yunit-lyrics-sharpen[disabled] {
color: #6e6760;
border-color: #3a363f;
}
html[dark] .yunit-lyrics-sharpen[data-state="done"][data-mode="sharp"] {
color: hsl(355, 60%, 80%);
border-color: hsla(355, 50%, 60%, 0.4);
background: hsla(355, 45%, 50%, 0.1);
}
html[dark] .yunit-lyrics-sharpen[data-state="done"][data-mode="nmt"] {
color: #8a8275;
border-color: #4a4550;
background: transparent;
}
html[dark] .yunit-lyrics-nudge { border-color: #4a4550; }
html[dark] .yunit-lyrics-nudge[data-active="true"] {
border-color: hsla(355, 50%, 60%, 0.5);
background: hsla(355, 45%, 50%, 0.12);
}
html[dark] .yunit-lyrics-nudge-back,
html[dark] .yunit-lyrics-nudge-fwd { color: #a89f8d; }
html[dark] .yunit-lyrics-nudge-back:hover,
html[dark] .yunit-lyrics-nudge-fwd:hover {
background: hsla(355, 45%, 50%, 0.18);
color: hsl(355, 60%, 84%);
}
html[dark] .yunit-lyrics-nudge-value {
color: #8a8275;
border-color: #3a363f;
}
html[dark] .yunit-lyrics-nudge[data-active="true"] .yunit-lyrics-nudge-value {
color: hsl(355, 60%, 84%);
border-color: hsla(355, 50%, 60%, 0.35);
}
html[dark] .yunit-lyrics-appearance-menu {
background: #26232a;
border-color: #3a363f;
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.5);
}
html[dark] .yunit-lyrics-appearance-label { color: #8a8275; }
html[dark] .yunit-lyrics-appearance-options button {
border-color: #4a4550;
color: #a89f8d;
}
html[dark] .yunit-lyrics-appearance-options button:hover {
color: hsl(355, 60%, 82%);
border-color: hsla(355, 50%, 60%, 0.5);
}
html[dark] .yunit-lyrics-appearance-options button[data-active="true"],
html[dark] .yunit-lyrics-appearance-options button[data-on="true"] {
color: hsl(355, 60%, 84%);
background: hsla(355, 45%, 50%, 0.18);
border-color: hsla(355, 50%, 60%, 0.5);
}
html[dark] .yunit-lyrics-appearance-swatches button {
box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.12);
}
html[dark] .yunit-lyrics-appearance-swatches button[data-active="true"] {
border-color: hsl(355, 60%, 65%);
box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.12),
0 0 0 2px hsla(355, 60%, 65%, 0.3);
}
html[dark] .yunit-lyrics-picker-btn {

@@ -1543,0 +1771,0 @@ color: #ddd9d2;

@@ -9,3 +9,9 @@ (() => {

// "lemma migration done" flag. Kept indefinitely as a safety net.
preLemmaSnapshot: "yunit.vocab.preLemma"
preLemmaSnapshot: "yunit.vocab.preLemma",
// Per-video lyrics state, both LRU-capped maps keyed by YT video id.
// Nudges: the manual sync offset the user dialed in, so a rewatch
// doesn't make them re-tune. Cache: the resolved LRCLIB payload, so a
// rewatch renders instantly without re-hitting the API.
lyricsNudges: "yunit.lyrics.nudges",
lyricsCache: "yunit.lyrics.cache"
};

@@ -167,3 +173,18 @@ var extDead = false;

// default surface rather than an Alt+Shift+L away.
lyricsAutoOpen: false
lyricsAutoOpen: false,
// On-video karaoke overlay appearance. Style picks the contrast strategy
// against the footage: 'shadow' (soft dark halo, the original), 'outline'
// (hard stroke, holds up on mid-brightness video), 'plate' (caption-style
// scrim behind the text — readable on anything). Color is a small curated
// palette of light inks; size multiplies the player-width-derived base
// font. nextLine shows the upcoming lyric dimmed under the current one.
// Controls live in the lyrics panel header, not the popup — appearance
// is tuned while watching.
lyricsOverlayStyle: "shadow",
// 'shadow' | 'outline' | 'plate'
lyricsOverlayColor: "white",
// 'white' | 'cream' | 'yellow' | 'cyan'
lyricsOverlaySize: "medium",
// 'small' | 'medium' | 'large'
lyricsOverlayNextLine: false
};

@@ -170,0 +191,0 @@ var settings = { ...DEFAULTS };

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display