@aicut/core 0.1.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +29 -0
- package/dist/chunk-CCDON7CU.js +87 -0
- package/dist/chunk-CCDON7CU.js.map +1 -0
- package/dist/index.d.cts +3 -119
- package/dist/index.d.ts +3 -119
- package/dist/index.js +4 -85
- package/dist/index.js.map +1 -1
- package/dist/lighting/index.cjs +19223 -0
- package/dist/lighting/index.cjs.map +1 -0
- package/dist/lighting/index.d.cts +135 -0
- package/dist/lighting/index.d.ts +135 -0
- package/dist/lighting/index.js +19160 -0
- package/dist/lighting/index.js.map +1 -0
- package/dist/types-C95koNwJ.d.cts +120 -0
- package/dist/types-C95koNwJ.d.ts +120 -0
- package/package.json +15 -3
- package/styles/theme.css +239 -0
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* UI strings the editor paints into the DOM (toolbar tooltips, the
|
|
3
|
+
* fullscreen exit button) and onto the timeline canvas (phantom new-
|
|
4
|
+
* track label, track header labels). Every user-visible literal in
|
|
5
|
+
* `@aicut/core` flows through this interface — there are no hidden
|
|
6
|
+
* hard-coded translations elsewhere in the library.
|
|
7
|
+
*
|
|
8
|
+
* Defaults to English. Hosts that want Chinese (or any other locale)
|
|
9
|
+
* pass `locale: localeZh` to `Editor.create` / `Timeline.create`, or
|
|
10
|
+
* override individual keys with `locale: { undo: "撤销" }`.
|
|
11
|
+
*/
|
|
12
|
+
interface Locale {
|
|
13
|
+
undo: string;
|
|
14
|
+
redo: string;
|
|
15
|
+
split: string;
|
|
16
|
+
trimLeft: string;
|
|
17
|
+
trimRight: string;
|
|
18
|
+
speedComingSoon: string;
|
|
19
|
+
playPause: string;
|
|
20
|
+
fullscreen: string;
|
|
21
|
+
snap: string;
|
|
22
|
+
/** Title shown on the snap button when snap is ON (clicking turns OFF). */
|
|
23
|
+
snapOnTitle: string;
|
|
24
|
+
/** Title shown when snap is OFF (clicking turns ON). */
|
|
25
|
+
snapOffTitle: string;
|
|
26
|
+
zoomOut: string;
|
|
27
|
+
zoomIn: string;
|
|
28
|
+
reset: string;
|
|
29
|
+
exitFullscreen: string;
|
|
30
|
+
exitFullscreenTitle: string;
|
|
31
|
+
/** Phantom row that appears under the last track during a drag. */
|
|
32
|
+
newTrack: string;
|
|
33
|
+
/** Track header — `{n}` is replaced with the 1-based track index. */
|
|
34
|
+
videoTrackLabel: string;
|
|
35
|
+
/** Same template format as videoTrackLabel. */
|
|
36
|
+
audioTrackLabel: string;
|
|
37
|
+
}
|
|
38
|
+
/** English. The library default — chosen over Chinese as the OSS norm. */
|
|
39
|
+
declare const localeEn: Locale;
|
|
40
|
+
/** Simplified Chinese. */
|
|
41
|
+
declare const localeZh: Locale;
|
|
42
|
+
/** Spread defaults under host overrides — host can supply a partial. */
|
|
43
|
+
declare function mergeLocale(partial: Partial<Locale> | undefined): Locale;
|
|
44
|
+
/**
|
|
45
|
+
* Replace `{key}` placeholders in a template. We only need `{n}`
|
|
46
|
+
* substitution today; the implementation is generic so additional
|
|
47
|
+
* keys (e.g. `{name}`) won't need a second pass.
|
|
48
|
+
*/
|
|
49
|
+
declare function formatLabel(template: string, vars: Record<string, string | number>): string;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Milliseconds. All timing in the project is expressed as integer ms to
|
|
53
|
+
* keep JSON serialization unambiguous (no frame-rate coupling in the
|
|
54
|
+
* data model — the renderer can present time as frames if it wants).
|
|
55
|
+
*/
|
|
56
|
+
type Ms = number;
|
|
57
|
+
interface MediaSource {
|
|
58
|
+
id: string;
|
|
59
|
+
url: string;
|
|
60
|
+
kind: "video" | "audio";
|
|
61
|
+
/** Optional — probed lazily from the <video> element if absent. */
|
|
62
|
+
duration?: Ms;
|
|
63
|
+
name?: string;
|
|
64
|
+
}
|
|
65
|
+
interface Clip {
|
|
66
|
+
id: string;
|
|
67
|
+
sourceId: string;
|
|
68
|
+
/** Window into the source — `in` inclusive, `out` exclusive. */
|
|
69
|
+
in: Ms;
|
|
70
|
+
out: Ms;
|
|
71
|
+
/** Position on the timeline. */
|
|
72
|
+
start: Ms;
|
|
73
|
+
/**
|
|
74
|
+
* Playback rate. 1 = normal, 2 = 2× speed. Default 1.
|
|
75
|
+
* Persisted in the project JSON so a host can restore exactly.
|
|
76
|
+
*/
|
|
77
|
+
speed?: number;
|
|
78
|
+
}
|
|
79
|
+
interface Track {
|
|
80
|
+
id: string;
|
|
81
|
+
kind: "video" | "audio";
|
|
82
|
+
/** Clips on this track. Must be kept sorted by `start` and non-overlapping. */
|
|
83
|
+
clips: Clip[];
|
|
84
|
+
}
|
|
85
|
+
interface Project {
|
|
86
|
+
/** Schema version — bump when breaking the JSON shape. */
|
|
87
|
+
version: 1;
|
|
88
|
+
sources: MediaSource[];
|
|
89
|
+
tracks: Track[];
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Subset of CSS variables the editor honors. Pass any custom values
|
|
93
|
+
* via `Editor` options; everything is forwarded as `--aicut-*` on the
|
|
94
|
+
* editor's root container, so a host can also override via plain CSS.
|
|
95
|
+
*/
|
|
96
|
+
interface Theme {
|
|
97
|
+
brand?: string;
|
|
98
|
+
secondary?: string;
|
|
99
|
+
surface?: string;
|
|
100
|
+
dark?: string;
|
|
101
|
+
muted?: string;
|
|
102
|
+
card?: string;
|
|
103
|
+
success?: string;
|
|
104
|
+
warning?: string;
|
|
105
|
+
info?: string;
|
|
106
|
+
error?: string;
|
|
107
|
+
/** Toolbar / ruler chrome. Background of the editor frame. */
|
|
108
|
+
controlsBg?: string;
|
|
109
|
+
controlsBorder?: string;
|
|
110
|
+
controlsText?: string;
|
|
111
|
+
controlsHover?: string;
|
|
112
|
+
controlsActive?: string;
|
|
113
|
+
/** Letterbox color around the preview video. Defaults to black. */
|
|
114
|
+
previewBg?: string;
|
|
115
|
+
radiusSm?: string;
|
|
116
|
+
radiusMd?: string;
|
|
117
|
+
radiusLg?: string;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export { type Clip as C, type Locale as L, type Ms as M, type Project as P, type Track as T, type MediaSource as a, type Theme as b, localeZh as c, formatLabel as f, localeEn as l, mergeLocale as m };
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* UI strings the editor paints into the DOM (toolbar tooltips, the
|
|
3
|
+
* fullscreen exit button) and onto the timeline canvas (phantom new-
|
|
4
|
+
* track label, track header labels). Every user-visible literal in
|
|
5
|
+
* `@aicut/core` flows through this interface — there are no hidden
|
|
6
|
+
* hard-coded translations elsewhere in the library.
|
|
7
|
+
*
|
|
8
|
+
* Defaults to English. Hosts that want Chinese (or any other locale)
|
|
9
|
+
* pass `locale: localeZh` to `Editor.create` / `Timeline.create`, or
|
|
10
|
+
* override individual keys with `locale: { undo: "撤销" }`.
|
|
11
|
+
*/
|
|
12
|
+
interface Locale {
|
|
13
|
+
undo: string;
|
|
14
|
+
redo: string;
|
|
15
|
+
split: string;
|
|
16
|
+
trimLeft: string;
|
|
17
|
+
trimRight: string;
|
|
18
|
+
speedComingSoon: string;
|
|
19
|
+
playPause: string;
|
|
20
|
+
fullscreen: string;
|
|
21
|
+
snap: string;
|
|
22
|
+
/** Title shown on the snap button when snap is ON (clicking turns OFF). */
|
|
23
|
+
snapOnTitle: string;
|
|
24
|
+
/** Title shown when snap is OFF (clicking turns ON). */
|
|
25
|
+
snapOffTitle: string;
|
|
26
|
+
zoomOut: string;
|
|
27
|
+
zoomIn: string;
|
|
28
|
+
reset: string;
|
|
29
|
+
exitFullscreen: string;
|
|
30
|
+
exitFullscreenTitle: string;
|
|
31
|
+
/** Phantom row that appears under the last track during a drag. */
|
|
32
|
+
newTrack: string;
|
|
33
|
+
/** Track header — `{n}` is replaced with the 1-based track index. */
|
|
34
|
+
videoTrackLabel: string;
|
|
35
|
+
/** Same template format as videoTrackLabel. */
|
|
36
|
+
audioTrackLabel: string;
|
|
37
|
+
}
|
|
38
|
+
/** English. The library default — chosen over Chinese as the OSS norm. */
|
|
39
|
+
declare const localeEn: Locale;
|
|
40
|
+
/** Simplified Chinese. */
|
|
41
|
+
declare const localeZh: Locale;
|
|
42
|
+
/** Spread defaults under host overrides — host can supply a partial. */
|
|
43
|
+
declare function mergeLocale(partial: Partial<Locale> | undefined): Locale;
|
|
44
|
+
/**
|
|
45
|
+
* Replace `{key}` placeholders in a template. We only need `{n}`
|
|
46
|
+
* substitution today; the implementation is generic so additional
|
|
47
|
+
* keys (e.g. `{name}`) won't need a second pass.
|
|
48
|
+
*/
|
|
49
|
+
declare function formatLabel(template: string, vars: Record<string, string | number>): string;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Milliseconds. All timing in the project is expressed as integer ms to
|
|
53
|
+
* keep JSON serialization unambiguous (no frame-rate coupling in the
|
|
54
|
+
* data model — the renderer can present time as frames if it wants).
|
|
55
|
+
*/
|
|
56
|
+
type Ms = number;
|
|
57
|
+
interface MediaSource {
|
|
58
|
+
id: string;
|
|
59
|
+
url: string;
|
|
60
|
+
kind: "video" | "audio";
|
|
61
|
+
/** Optional — probed lazily from the <video> element if absent. */
|
|
62
|
+
duration?: Ms;
|
|
63
|
+
name?: string;
|
|
64
|
+
}
|
|
65
|
+
interface Clip {
|
|
66
|
+
id: string;
|
|
67
|
+
sourceId: string;
|
|
68
|
+
/** Window into the source — `in` inclusive, `out` exclusive. */
|
|
69
|
+
in: Ms;
|
|
70
|
+
out: Ms;
|
|
71
|
+
/** Position on the timeline. */
|
|
72
|
+
start: Ms;
|
|
73
|
+
/**
|
|
74
|
+
* Playback rate. 1 = normal, 2 = 2× speed. Default 1.
|
|
75
|
+
* Persisted in the project JSON so a host can restore exactly.
|
|
76
|
+
*/
|
|
77
|
+
speed?: number;
|
|
78
|
+
}
|
|
79
|
+
interface Track {
|
|
80
|
+
id: string;
|
|
81
|
+
kind: "video" | "audio";
|
|
82
|
+
/** Clips on this track. Must be kept sorted by `start` and non-overlapping. */
|
|
83
|
+
clips: Clip[];
|
|
84
|
+
}
|
|
85
|
+
interface Project {
|
|
86
|
+
/** Schema version — bump when breaking the JSON shape. */
|
|
87
|
+
version: 1;
|
|
88
|
+
sources: MediaSource[];
|
|
89
|
+
tracks: Track[];
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Subset of CSS variables the editor honors. Pass any custom values
|
|
93
|
+
* via `Editor` options; everything is forwarded as `--aicut-*` on the
|
|
94
|
+
* editor's root container, so a host can also override via plain CSS.
|
|
95
|
+
*/
|
|
96
|
+
interface Theme {
|
|
97
|
+
brand?: string;
|
|
98
|
+
secondary?: string;
|
|
99
|
+
surface?: string;
|
|
100
|
+
dark?: string;
|
|
101
|
+
muted?: string;
|
|
102
|
+
card?: string;
|
|
103
|
+
success?: string;
|
|
104
|
+
warning?: string;
|
|
105
|
+
info?: string;
|
|
106
|
+
error?: string;
|
|
107
|
+
/** Toolbar / ruler chrome. Background of the editor frame. */
|
|
108
|
+
controlsBg?: string;
|
|
109
|
+
controlsBorder?: string;
|
|
110
|
+
controlsText?: string;
|
|
111
|
+
controlsHover?: string;
|
|
112
|
+
controlsActive?: string;
|
|
113
|
+
/** Letterbox color around the preview video. Defaults to black. */
|
|
114
|
+
previewBg?: string;
|
|
115
|
+
radiusSm?: string;
|
|
116
|
+
radiusMd?: string;
|
|
117
|
+
radiusLg?: string;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export { type Clip as C, type Locale as L, type Ms as M, type Project as P, type Track as T, type MediaSource as a, type Theme as b, localeZh as c, formatLabel as f, localeEn as l, mergeLocale as m };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aicut/core",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Framework-agnostic core for the AiCut video editor — canvas timeline, data model, HTML5 playback engine.",
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "Framework-agnostic core for the AiCut video editor — canvas timeline, data model, HTML5 playback engine, plus an opt-in 3D lighting picker.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "ziqiang <ziqiangytu@gmail.com>",
|
|
7
7
|
"homepage": "https://github.com/ziqiangai/AiCut#readme",
|
|
@@ -34,7 +34,10 @@
|
|
|
34
34
|
"davinci",
|
|
35
35
|
"imovie",
|
|
36
36
|
"veed",
|
|
37
|
-
"filmora"
|
|
37
|
+
"filmora",
|
|
38
|
+
"lighting",
|
|
39
|
+
"three.js",
|
|
40
|
+
"ai-relighting"
|
|
38
41
|
],
|
|
39
42
|
"type": "module",
|
|
40
43
|
"sideEffects": [
|
|
@@ -49,6 +52,11 @@
|
|
|
49
52
|
"import": "./dist/index.js",
|
|
50
53
|
"require": "./dist/index.cjs"
|
|
51
54
|
},
|
|
55
|
+
"./lighting": {
|
|
56
|
+
"types": "./dist/lighting/index.d.ts",
|
|
57
|
+
"import": "./dist/lighting/index.js",
|
|
58
|
+
"require": "./dist/lighting/index.cjs"
|
|
59
|
+
},
|
|
52
60
|
"./styles.css": "./styles/theme.css"
|
|
53
61
|
},
|
|
54
62
|
"files": [
|
|
@@ -56,7 +64,11 @@
|
|
|
56
64
|
"styles",
|
|
57
65
|
"README.md"
|
|
58
66
|
],
|
|
67
|
+
"dependencies": {
|
|
68
|
+
"three": "^0.159.0"
|
|
69
|
+
},
|
|
59
70
|
"devDependencies": {
|
|
71
|
+
"@types/three": "^0.159.0",
|
|
60
72
|
"tsup": "^8.3.5",
|
|
61
73
|
"typescript": "^5.7.2"
|
|
62
74
|
},
|
package/styles/theme.css
CHANGED
|
@@ -412,3 +412,242 @@
|
|
|
412
412
|
.aicut-timeline-toolbar-right {
|
|
413
413
|
margin-left: auto;
|
|
414
414
|
}
|
|
415
|
+
|
|
416
|
+
/* ===== Lighting editor (opt-in component) ===== */
|
|
417
|
+
|
|
418
|
+
/* IMPORTANT: every `var(--aicut-controls-*)` reference below carries
|
|
419
|
+
an explicit fallback (the same value the .aicut-root rule would
|
|
420
|
+
compute via its self-reference pattern). Chrome treats the
|
|
421
|
+
self-reference `--foo: var(--foo, x)` on .aicut-root as a cycle
|
|
422
|
+
and skips it when no parent + no inline override defines `--foo`
|
|
423
|
+
— which means the lighting component must NOT depend on those
|
|
424
|
+
inherited custom properties succeeding. The video editor sidesteps
|
|
425
|
+
the issue because applyTheme() always writes the values inline.
|
|
426
|
+
Hosts that pass a `theme` prop or set the --aicut-controls-* vars
|
|
427
|
+
themselves still override these fallbacks; it's pure belt-and-
|
|
428
|
+
braces. */
|
|
429
|
+
|
|
430
|
+
.aicut-lighting-editor {
|
|
431
|
+
--aicut-lighting-canvas-bg: color-mix(in srgb, var(--aicut-controls-text, rgba(255, 255, 255, 0.85)) 4%, transparent);
|
|
432
|
+
--aicut-lighting-section-gap: 14px;
|
|
433
|
+
--aicut-lighting-control-w: 220px;
|
|
434
|
+
display: block;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
.aicut-lighting-body {
|
|
438
|
+
display: grid;
|
|
439
|
+
/* Just two columns: scene 240 + controls 220. Hosts that want to
|
|
440
|
+
render an adjacent panel (AI smart mode, prompt, presets, …) put
|
|
441
|
+
their own DOM beside <LightingEditor> in their own layout. */
|
|
442
|
+
grid-template-columns: 240px 220px;
|
|
443
|
+
gap: 16px;
|
|
444
|
+
align-items: start;
|
|
445
|
+
padding: 16px;
|
|
446
|
+
background: var(--aicut-controls-bg, #1f1f22);
|
|
447
|
+
color: var(--aicut-controls-text, rgba(255, 255, 255, 0.85));
|
|
448
|
+
border-radius: var(--aicut-radius-md, 12px);
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
/* --- Scene column --- */
|
|
452
|
+
.aicut-lighting-scene-col {
|
|
453
|
+
display: flex;
|
|
454
|
+
flex-direction: column;
|
|
455
|
+
align-items: center;
|
|
456
|
+
gap: 8px;
|
|
457
|
+
/* Self-center vertically so the sphere stays at the visual midpoint
|
|
458
|
+
of the row even when the smart drawer stretches the row taller
|
|
459
|
+
than the scene column's own content. */
|
|
460
|
+
align-self: center;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
.aicut-lighting-view-toggle {
|
|
464
|
+
display: inline-flex;
|
|
465
|
+
padding: 2px;
|
|
466
|
+
border-radius: 999px;
|
|
467
|
+
background: var(--aicut-controls-active, rgba(255, 255, 255, 0.12));
|
|
468
|
+
position: relative;
|
|
469
|
+
}
|
|
470
|
+
.aicut-lighting-view-opt {
|
|
471
|
+
height: 24px;
|
|
472
|
+
padding: 0 12px;
|
|
473
|
+
border: 0;
|
|
474
|
+
background: transparent;
|
|
475
|
+
font: inherit;
|
|
476
|
+
font-size: 12px;
|
|
477
|
+
color: var(--aicut-controls-text, rgba(255, 255, 255, 0.85));
|
|
478
|
+
opacity: 0.6;
|
|
479
|
+
border-radius: 999px;
|
|
480
|
+
cursor: pointer;
|
|
481
|
+
transition: opacity 120ms ease, background-color 120ms ease;
|
|
482
|
+
}
|
|
483
|
+
.aicut-lighting-view-opt.active {
|
|
484
|
+
background: var(--aicut-controls-bg, #1f1f22);
|
|
485
|
+
opacity: 1;
|
|
486
|
+
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.15);
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
.aicut-lighting-scene-viewport {
|
|
490
|
+
width: 100%;
|
|
491
|
+
max-width: 240px;
|
|
492
|
+
aspect-ratio: 1;
|
|
493
|
+
border-radius: 50%;
|
|
494
|
+
overflow: hidden;
|
|
495
|
+
background: var(--aicut-lighting-canvas-bg);
|
|
496
|
+
position: relative;
|
|
497
|
+
/* Keep the canvas filling the viewport even before ResizeObserver
|
|
498
|
+
fires the first measurement. */
|
|
499
|
+
display: flex;
|
|
500
|
+
align-items: center;
|
|
501
|
+
justify-content: center;
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
/* --- Controls column --- */
|
|
505
|
+
.aicut-lighting-controls {
|
|
506
|
+
display: flex;
|
|
507
|
+
flex-direction: column;
|
|
508
|
+
gap: var(--aicut-lighting-section-gap);
|
|
509
|
+
min-width: 0;
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
.aicut-lighting-controls-header {
|
|
513
|
+
display: flex;
|
|
514
|
+
align-items: center;
|
|
515
|
+
justify-content: space-between;
|
|
516
|
+
gap: 8px;
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
.aicut-lighting-controls-title {
|
|
520
|
+
font-size: 13px;
|
|
521
|
+
font-weight: 600;
|
|
522
|
+
color: var(--aicut-controls-text, rgba(255, 255, 255, 0.85));
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
.aicut-lighting-controls-header-slot {
|
|
526
|
+
display: flex;
|
|
527
|
+
align-items: center;
|
|
528
|
+
gap: 8px;
|
|
529
|
+
margin-left: auto;
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
.aicut-lighting-section {
|
|
533
|
+
display: flex;
|
|
534
|
+
flex-direction: column;
|
|
535
|
+
gap: 6px;
|
|
536
|
+
}
|
|
537
|
+
.aicut-lighting-section-row {
|
|
538
|
+
flex-direction: row;
|
|
539
|
+
align-items: center;
|
|
540
|
+
justify-content: space-between;
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
.aicut-lighting-label {
|
|
544
|
+
font-size: 12px;
|
|
545
|
+
color: color-mix(in srgb, var(--aicut-controls-text, rgba(255, 255, 255, 0.85)) 70%, transparent);
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
.aicut-lighting-range {
|
|
549
|
+
appearance: none;
|
|
550
|
+
-webkit-appearance: none;
|
|
551
|
+
width: 100%;
|
|
552
|
+
height: 4px;
|
|
553
|
+
border-radius: 999px;
|
|
554
|
+
background: color-mix(in srgb, var(--aicut-controls-text, rgba(255, 255, 255, 0.85)) 18%, transparent);
|
|
555
|
+
outline: none;
|
|
556
|
+
}
|
|
557
|
+
.aicut-lighting-range::-webkit-slider-thumb {
|
|
558
|
+
appearance: none;
|
|
559
|
+
-webkit-appearance: none;
|
|
560
|
+
width: 14px;
|
|
561
|
+
height: 14px;
|
|
562
|
+
border-radius: 50%;
|
|
563
|
+
background: var(--aicut-controls-text, rgba(255, 255, 255, 0.85));
|
|
564
|
+
cursor: pointer;
|
|
565
|
+
}
|
|
566
|
+
.aicut-lighting-range::-moz-range-thumb {
|
|
567
|
+
width: 14px;
|
|
568
|
+
height: 14px;
|
|
569
|
+
border: 0;
|
|
570
|
+
border-radius: 50%;
|
|
571
|
+
background: var(--aicut-controls-text, rgba(255, 255, 255, 0.85));
|
|
572
|
+
cursor: pointer;
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
.aicut-lighting-color {
|
|
576
|
+
width: 44px;
|
|
577
|
+
height: 24px;
|
|
578
|
+
padding: 0;
|
|
579
|
+
border: 1px solid var(--aicut-controls-border, rgba(255, 255, 255, 0.08));
|
|
580
|
+
border-radius: 6px;
|
|
581
|
+
background: transparent;
|
|
582
|
+
cursor: pointer;
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
.aicut-lighting-dir-grid {
|
|
586
|
+
display: grid;
|
|
587
|
+
grid-template-columns: repeat(3, 1fr);
|
|
588
|
+
gap: 6px;
|
|
589
|
+
}
|
|
590
|
+
.aicut-lighting-dir-btn {
|
|
591
|
+
height: 28px;
|
|
592
|
+
padding: 0 4px;
|
|
593
|
+
border: 1px solid var(--aicut-controls-border, rgba(255, 255, 255, 0.08));
|
|
594
|
+
border-radius: 6px;
|
|
595
|
+
background: transparent;
|
|
596
|
+
color: var(--aicut-controls-text, rgba(255, 255, 255, 0.85));
|
|
597
|
+
font: inherit;
|
|
598
|
+
font-size: 12px;
|
|
599
|
+
cursor: pointer;
|
|
600
|
+
transition: background-color 120ms ease, border-color 120ms ease;
|
|
601
|
+
}
|
|
602
|
+
.aicut-lighting-dir-btn:hover {
|
|
603
|
+
background: var(--aicut-controls-hover, rgba(255, 255, 255, 0.08));
|
|
604
|
+
}
|
|
605
|
+
.aicut-lighting-dir-btn.active {
|
|
606
|
+
background: color-mix(in srgb, var(--color-brand, #ff3386) 18%, transparent);
|
|
607
|
+
border-color: var(--color-brand, #ff3386);
|
|
608
|
+
color: var(--color-brand, #ff3386);
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
.aicut-lighting-toggle {
|
|
612
|
+
width: 32px;
|
|
613
|
+
height: 18px;
|
|
614
|
+
border-radius: 999px;
|
|
615
|
+
background: color-mix(in srgb, var(--aicut-controls-text, rgba(255, 255, 255, 0.85)) 18%, transparent);
|
|
616
|
+
position: relative;
|
|
617
|
+
cursor: pointer;
|
|
618
|
+
transition: background-color 120ms ease;
|
|
619
|
+
}
|
|
620
|
+
.aicut-lighting-toggle.active {
|
|
621
|
+
background: var(--color-brand, #ff3386);
|
|
622
|
+
}
|
|
623
|
+
.aicut-lighting-toggle-thumb {
|
|
624
|
+
width: 14px;
|
|
625
|
+
height: 14px;
|
|
626
|
+
border-radius: 50%;
|
|
627
|
+
background: #fff;
|
|
628
|
+
position: absolute;
|
|
629
|
+
top: 2px;
|
|
630
|
+
left: 2px;
|
|
631
|
+
transition: left 120ms ease;
|
|
632
|
+
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
|
|
633
|
+
}
|
|
634
|
+
.aicut-lighting-toggle.active .aicut-lighting-toggle-thumb {
|
|
635
|
+
left: 16px;
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
.aicut-lighting-reset {
|
|
639
|
+
margin-left: auto;
|
|
640
|
+
height: 28px;
|
|
641
|
+
padding: 0 12px;
|
|
642
|
+
border: 1px solid var(--aicut-controls-border, rgba(255, 255, 255, 0.08));
|
|
643
|
+
border-radius: 6px;
|
|
644
|
+
background: transparent;
|
|
645
|
+
color: var(--aicut-controls-text, rgba(255, 255, 255, 0.85));
|
|
646
|
+
font: inherit;
|
|
647
|
+
font-size: 12px;
|
|
648
|
+
cursor: pointer;
|
|
649
|
+
}
|
|
650
|
+
.aicut-lighting-reset:hover {
|
|
651
|
+
background: var(--aicut-controls-hover, rgba(255, 255, 255, 0.08));
|
|
652
|
+
}
|
|
653
|
+
|