├── .gitmodules
├── LICENSE
├── gsui.css
├── gsui0ne
└── gsui0ne.js
├── gsuiActionMenu
├── gsuiActionMenu.css
├── gsuiActionMenu.js
└── index.html
├── gsuiAnalyserHist
├── gsuiAnalyserHist.css
├── gsuiAnalyserHist.js
└── index.html
├── gsuiAnalyserHz
├── gsuiAnalyserHz.js
└── index.html
├── gsuiAnalyserTd
├── gsuiAnalyserTd.js
└── index.html
├── gsuiAnalyserVu
├── gsuiAnalyserVu.css
├── gsuiAnalyserVu.html.js
├── gsuiAnalyserVu.js
└── index.html
├── gsuiBeatlines
├── gsuiBeatlines.css
├── gsuiBeatlines.html.js
├── gsuiBeatlines.js
└── index.html
├── gsuiBlocksManager
├── gsuiBlocksManager.css
└── gsuiBlocksManager.js
├── gsuiChannel
├── gsuiChannel.css
├── gsuiChannel.html.js
├── gsuiChannel.js
└── index.html
├── gsuiChannels
├── gsuiChannels.css
├── gsuiChannels.html.js
└── gsuiChannels.js
├── gsuiClock
├── gsuiClock.css
├── gsuiClock.html.js
├── gsuiClock.js
└── index.html
├── gsuiComAvatar
├── gsuiComAvatar.css
├── gsuiComAvatar.js
└── index.html
├── gsuiComButton
├── gsuiComButton.css
├── gsuiComButton.js
└── index.html
├── gsuiComPlayer
├── gsuiComPlayer.css
├── gsuiComPlayer.html.js
├── gsuiComPlayer.js
└── index.html
├── gsuiComPlaylist
├── gsuiComPlaylist.css
├── gsuiComPlaylist.html.js
├── gsuiComPlaylist.js
└── index.html
├── gsuiComProfile
├── gsuiComProfile.css
├── gsuiComProfile.html.js
├── gsuiComProfile.js
└── index.html
├── gsuiCurves
├── gsuiCurves.css
├── gsuiCurves.html.js
└── gsuiCurves.js
├── gsuiDAW
├── gsuiDAW-btn.css
├── gsuiDAW-head.css
├── gsuiDAW-popup-about.css
├── gsuiDAW-popup-about.html.js
├── gsuiDAW-popup-export.css
├── gsuiDAW-popup-export.html.js
├── gsuiDAW-popup-settings.css
├── gsuiDAW-popup-settings.html.js
├── gsuiDAW-windows.css
├── gsuiDAW-windows.html.js
├── gsuiDAW.css
├── gsuiDAW.html.js
├── gsuiDAW.js
└── index.html
├── gsuiDotline
├── gsuiDotline.css
├── gsuiDotline.html.js
├── gsuiDotline.js
└── index.html
├── gsuiDotlineSVG
├── gsuiDotlineSVG.html.js
└── gsuiDotlineSVG.js
├── gsuiDragline
├── gsuiDragline.css
├── gsuiDragline.html.js
└── gsuiDragline.js
├── gsuiDropdown
├── getAbsPos.js
├── gsuiDropdown.css
└── gsuiDropdown.js
├── gsuiDrum
├── gsuiDrum.css
├── gsuiDrum.html.js
├── gsuiDrum.js
└── gsuiDrumcut.js
├── gsuiDrumrow
├── gsuiDrumrow.css
├── gsuiDrumrow.html.js
└── gsuiDrumrow.js
├── gsuiDrumrows
├── gsuiDrumrows.css
├── gsuiDrumrows.js
└── index.html
├── gsuiDrums
├── gsuiDrums.css
├── gsuiDrums.html.js
├── gsuiDrums.js
└── index.html
├── gsuiEffect
├── gsuiEffect.css
├── gsuiEffect.html.js
└── gsuiEffect.js
├── gsuiEffects
├── gsuiEffects.css
├── gsuiEffects.html.js
└── gsuiEffects.js
├── gsuiEnvelope
├── gsuiEnvelope.css
├── gsuiEnvelope.html.js
├── gsuiEnvelope.js
└── index.html
├── gsuiEnvelopeGraph
├── gsuiEnvelopeGraph.css
├── gsuiEnvelopeGraph.html.js
└── gsuiEnvelopeGraph.js
├── gsuiFxDelay
├── gsuiFxDelay.css
├── gsuiFxDelay.html.js
├── gsuiFxDelay.js
└── index.html
├── gsuiFxFilter
├── gsuiFxFilter.css
├── gsuiFxFilter.html.js
├── gsuiFxFilter.js
└── index.html
├── gsuiFxReverb
├── gsuiFxReverb.css
├── gsuiFxReverb.html.js
├── gsuiFxReverb.js
└── index.html
├── gsuiFxWaveShaper
├── gsuiFxWaveShaper.css
├── gsuiFxWaveShaper.html.js
├── gsuiFxWaveShaper.js
└── index.html
├── gsuiGlitchText
├── gsuiGlitchText.css
├── gsuiGlitchText.html.js
├── gsuiGlitchText.js
└── index.html
├── gsuiHelpLink
├── gsuiHelpLink.css
└── gsuiHelpLink.js
├── gsuiIcon
└── gsuiIcon.css
├── gsuiKeys
├── gsuiKeys.css
├── gsuiKeys.html.js
├── gsuiKeys.js
└── index.html
├── gsuiLFO
├── gsuiLFO.css
├── gsuiLFO.html.js
├── gsuiLFO.js
└── index.html
├── gsuiLibraries
├── gsuiLibraries.css
├── gsuiLibraries.html.js
├── gsuiLibraries.js
└── index.html
├── gsuiLibrary
├── gsuiLibrary.css
├── gsuiLibrary.html.js
├── gsuiLibrary.js
└── index.html
├── gsuiMixer
├── gsuiMixer.css
├── gsuiMixer.html.js
├── gsuiMixer.js
└── index.html
├── gsuiNoise
├── gsuiNoise.css
├── gsuiNoise.html.js
├── gsuiNoise.js
└── index.html
├── gsuiOscillator
├── gsuiOscillator.css
├── gsuiOscillator.html.js
├── gsuiOscillator.js
└── index.html
├── gsuiPanels
├── gsuiPanels.css
├── gsuiPanels.js
└── index.html
├── gsuiPatternroll
├── gsuiPatternroll.css
├── gsuiPatternroll.html.js
└── gsuiPatternroll.js
├── gsuiPatterns
├── gsuiPatterns-infoPopup.html.js
├── gsuiPatterns-pattern.css
├── gsuiPatterns-pattern.html.js
├── gsuiPatterns-synth.css
├── gsuiPatterns-synth.html.js
├── gsuiPatterns.css
├── gsuiPatterns.html.js
└── gsuiPatterns.js
├── gsuiPeriodicWave
├── gsuiPeriodicWave.css
└── gsuiPeriodicWave.js
├── gsuiPianoroll
├── gsuiPianoroll-block.css
├── gsuiPianoroll.css
├── gsuiPianoroll.html.js
├── gsuiPianoroll.js
└── index.html
├── gsuiPopup
├── gsuiPopup.css
├── gsuiPopup.html.js
├── gsuiPopup.js
└── index.html
├── gsuiPropSelect
├── gsuiPropSelect.css
├── gsuiPropSelect.js
└── index.html
├── gsuiReorder
├── gsuiReorder.css
├── gsuiReorder.js
└── index.html
├── gsuiRipple
├── gsuiRipple.css
└── gsuiRipple.js
├── gsuiSVGPatterns
├── gsuiSVGPatterns.js
├── gsuiSVGPatternsAutomation.js
├── gsuiSVGPatternsDrums.js
├── gsuiSVGPatternsKeys.js
├── gsuiSVGPatternsSlices.js
└── index.html
├── gsuiScrollShadow
├── gsuiScrollShadow.css
├── gsuiScrollShadow.js
└── index.html
├── gsuiSkins
└── gsuiSkins-light.css
├── gsuiSlicer
├── gsuiSlicer.css
├── gsuiSlicer.html.js
├── gsuiSlicer.js
└── index.html
├── gsuiSlider
├── gsuiSlider.css
├── gsuiSlider.html.js
├── gsuiSlider.js
└── index.html
├── gsuiSliderGroup
├── gsuiSliderGroup.css
├── gsuiSliderGroup.html.js
├── gsuiSliderGroup.js
└── index.html
├── gsuiStepSelect
├── gsuiStepSelect.css
├── gsuiStepSelect.html.js
├── gsuiStepSelect.js
└── index.html
├── gsuiSynthesizer
├── gsuiSynthesizer.css
├── gsuiSynthesizer.html.js
├── gsuiSynthesizer.js
└── index.html
├── gsuiTempo
├── gsuiTempo.css
├── gsuiTempo.html.js
├── gsuiTempo.js
└── index.html
├── gsuiTimeline
├── gsuiTimeline.css
├── gsuiTimeline.html.js
├── gsuiTimeline.js
└── index.html
├── gsuiTimewindow
├── gsuiTimewindow.css
├── gsuiTimewindow.html.js
├── gsuiTimewindow.js
└── index.html
├── gsuiTitleUser
├── gsuiTitleUser.css
├── gsuiTitleUser.html.js
├── gsuiTitleUser.js
└── index.html
├── gsuiToggle
├── gsuiToggle.css
├── gsuiToggle.js
└── index.html
├── gsuiTrack
├── gsuiTrack.css
├── gsuiTrack.html.js
├── gsuiTrack.js
└── index.html
├── gsuiTracklist
└── gsuiTracklist.js
├── gsuiWaveform
└── gsuiWaveform.js
├── gsuiWavetable
├── gsuiWavetable.css
├── gsuiWavetable.html.js
├── gsuiWavetable.js
└── index.html
├── gsuiWavetableGraph
├── gsuiWavetableGraph.css
├── gsuiWavetableGraph.js
└── index.html
├── gsuiWindows
├── gsuiWindow.css
├── gsuiWindow.html.js
├── gsuiWindow.js
├── gsuiWindows.css
├── gsuiWindows.js
└── index.html
├── index.html
└── test-assets
├── 440-2.wav
├── 440-simple.wav
├── 440.wav
├── 808kick.wav
├── Cymatics-IcedOut.wav
├── Too Long - Steam Machine.wav
├── avatar.jpg
├── basssine.wav
├── clap-013.wav
├── hat-024.wav
├── kick-017.wav
├── okay.wav
├── openhat-012.wav
├── snare-018.wav
├── test.css
└── test.js
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "gs-utils"]
2 | path = gs-utils
3 | url = https://github.com/gridsound/gs-utils.git
4 | [submodule "assets"]
5 | path = assets
6 | url = https://github.com/gridsound/assets.git
7 |
--------------------------------------------------------------------------------
/gsuiActionMenu/gsuiActionMenu.css:
--------------------------------------------------------------------------------
1 | .gsuiActionMenu-actions {
2 | overflow: auto;
3 | }
4 |
5 | /* .......................................................................... */
6 | .gsuiActionMenu-action {
7 | display: flex;
8 | width: 100%;
9 | align-items: center;
10 | text-align: start;
11 | padding: 4px;
12 | border: 0;
13 | border-radius: 2px;
14 | gap: 6px;
15 | font-size: 14px;
16 | cursor: pointer;
17 | background: none;
18 | transition: .1s;
19 | transition-property: color, background-color;
20 | }
21 | .gsuiActionMenu-action:hover {
22 | /* color: #111;*/
23 | background-color: #fff2;
24 | }
25 | .gsuiActionMenu-action-body {
26 | display: flex;
27 | flex-direction: column;
28 | gap: 2px;
29 | }
30 | .gsuiActionMenu-action .gsuiIcon {
31 | width: 16px;
32 | min-width: 16px;
33 | }
34 | .gsuiActionMenu-action-name {
35 | font-weight: bold;
36 | }
37 | .gsuiActionMenu-action-desc {
38 | font-size: 12px;
39 | opacity: .7;
40 | }
41 |
--------------------------------------------------------------------------------
/gsuiActionMenu/gsuiActionMenu.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | class gsuiActionMenu {
4 | #dropdown = new gsuiDropdown();
5 | #minw = "100px";
6 | #minh = "32px";
7 | #maxw = "400px";
8 | #maxh = "400px";
9 | #actions = [];
10 | #onclickFn = GSUnoop;
11 | #closeAfterClick = true;
12 |
13 | constructor() {
14 | this.#dropdown.$onopenCreateElement( this.#createOptions.bind( this ) );
15 | this.#dropdown.$onbeforeOpening( () => {
16 | return this.#actions.length > 0;
17 | } );
18 | }
19 |
20 | // .........................................................................
21 | $open() { this.#dropdown.$open(); }
22 | $close() { this.#dropdown.$close(); }
23 | $bindTargetElement( btn ) { this.#dropdown.$bindTargetElement( btn ); }
24 | $setTarget( tar ) { this.#dropdown.$setTarget( tar ); }
25 | $setDirection( dir ) { this.#dropdown.$setDirection( dir ); }
26 | $setMenuParent( el ) { this.#dropdown.$setParent( el ); }
27 | $setMinSize( w, h ) {
28 | this.#minw = w;
29 | this.#minh = h;
30 | }
31 | $setMaxSize( w, h ) {
32 | this.#maxw = w;
33 | this.#maxh = h;
34 | }
35 | $setCallback( fn ) {
36 | this.#onclickFn = fn;
37 | }
38 | $closeAfterClick( b ) {
39 | this.#closeAfterClick = b;
40 | }
41 | $setActions( arr ) {
42 | this.#actions = arr.filter( Boolean ).map( act => ( { ...act } ) );
43 | }
44 | $changeAction( id, prop, val ) {
45 | const act = this.#actions.find( act => act.id === id );
46 | const elActions = this.#dropdown.$getContent();
47 |
48 | if ( act ) {
49 | act[ prop ] = val;
50 | if ( elActions ) {
51 | switch ( prop ) {
52 | case "icon":
53 | elActions.querySelector( `.gsuiActionMenu-action[data-id='${ act.id }'] .gsuiIcon` ).dataset.icon = val;
54 | break;
55 | }
56 | }
57 | }
58 | }
59 |
60 | // .........................................................................
61 | #onclickActions( e ) {
62 | const act = e.target.dataset.id;
63 |
64 | if ( act ) {
65 | this.#onclickFn( act );
66 | if ( this.#closeAfterClick ) {
67 | this.#dropdown.$close();
68 | }
69 | }
70 | }
71 | #createOptions() {
72 | const style = {
73 | minWidth: this.#minw,
74 | minHeight: this.#minh,
75 | maxWidth: this.#maxw,
76 | maxHeight: this.#maxh,
77 | };
78 | const elem = GSUcreateDiv( { class: "gsuiActionMenu-actions", style }, this.#actions.map( act =>
79 | !act.hidden && GSUcreateButton( { class: "gsuiActionMenu-action", "data-id": act.id },
80 | act.icon && GSUcreateIcon( { icon: act.icon } ),
81 | GSUcreateDiv( { class: "gsuiActionMenu-action-body", inert: true },
82 | GSUcreateSpan( { class: "gsuiActionMenu-action-name" }, act.name ),
83 | act.desc && GSUcreateSpan( { class: "gsuiActionMenu-action-desc" }, act.desc ),
84 | ),
85 | )
86 | ) );
87 |
88 | elem.onclick = this.#onclickActions.bind( this );
89 | return elem;
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/gsuiAnalyserHist/gsuiAnalyserHist.css:
--------------------------------------------------------------------------------
1 | gsui-analyser-hz,
2 | gsui-analyser-td,
3 | gsui-analyser-hist {
4 | display: flex;
5 | position: relative;
6 | overflow: hidden;
7 | height: 100%;
8 | background-color: var( --gsui-screen-spectrum );
9 | filter: var( --gsui-screen-spectrum-filter );
10 | }
11 |
12 | gsui-analyser-hz canvas,
13 | gsui-analyser-td canvas,
14 | gsui-analyser-hist canvas {
15 | position: absolute;
16 | width: 100%;
17 | height: 100%;
18 | }
19 |
20 | gsui-analyser-hist[ type="td" ]::after {
21 | position: absolute;
22 | content: "";
23 | width: 1px;
24 | height: 100%;
25 | left: 50%;
26 | background-color: #0004;
27 | }
28 |
--------------------------------------------------------------------------------
/gsuiAnalyserHz/gsuiAnalyserHz.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | class gsuiAnalyserHz extends gsui0ne {
4 | static #colors = [
5 | // datum R G B
6 | [ .99, 255, 255, 255 ],
7 | [ .98, 255, 255, 100 ],
8 | [ .97, 200, 200, 100 ],
9 | [ .95, 200, 200, 80 ],
10 | [ .9, 60, 90, 80 ],
11 | [ .8, 45, 45, 80 ],
12 | [ .7, 40, 40, 80 ],
13 | [ .6, 35, 35, 80 ],
14 | [ .4, 30, 30, 70 ],
15 | [ .3, 20, 20, 50 ],
16 | [ .25, 10, 10, 35 ],
17 | [ .17, 5, 5, 25 ],
18 | [ .1, 0, 0, 10 ],
19 | [ .01, 0, 0, 5 ],
20 | [ 0, 0, 0, 0 ],
21 | ];
22 | #ctx = null;
23 |
24 | constructor() {
25 | super( {
26 | $cmpName: "gsuiAnalyserHz",
27 | $tagName: "gsui-analyser-hz",
28 | $template: GSUcreateElement( "canvas", { inert: true } ),
29 | $attributes: {
30 | resolution: 256,
31 | },
32 | } );
33 | Object.seal( this );
34 | this.#ctx = this.$element.getContext( "2d" );
35 | }
36 |
37 | // .........................................................................
38 | static get observedAttributes() {
39 | return [ "resolution" ];
40 | }
41 | $attributeChanged( prop, val ) {
42 | switch ( prop ) {
43 | case "resolution":
44 | this.$element.width = +val;
45 | this.$element.height = 1;
46 | break;
47 | }
48 | }
49 |
50 | // .........................................................................
51 | $clear() {
52 | this.#ctx.clearRect( 0, 0, this.$element.width, 1 );
53 | }
54 | $draw( data ) {
55 | this.#ctx.putImageData( gsuiAnalyserHz.$draw( this.#ctx, data, this.$element.width ), 0, 0 );
56 | }
57 |
58 | // .........................................................................
59 | static $draw( ctx, data, width = data.length ) {
60 | const img = ctx.createImageData( width, 1 );
61 | const imgData = img.data;
62 |
63 | for ( let i = 0; i < width; ++i ) {
64 | const x = i * 4;
65 | const i2 = Math.round( GSUXtoHz( i / width ) * data.length );
66 | const datum = GSUmathEaseOutCirc( 1 - ( data[ i2 ] / -200 ) ) || 0;
67 | const [ , r, g, b ] = gsuiAnalyserHz.#colors.find( arr => arr[ 0 ] <= datum ) || gsuiAnalyserHz.#colors.at( -1 );
68 |
69 | imgData[ x ] = Math.min( r * datum, 255 ) | 0;
70 | imgData[ x + 1 ] = Math.min( g * datum, 255 ) | 0;
71 | imgData[ x + 2 ] = Math.min( b * datum, 255 ) | 0;
72 | imgData[ x + 3 ] = datum * 255;
73 | }
74 | return img;
75 | }
76 | }
77 |
78 | GSUdefineElement( "gsui-analyser-hz", gsuiAnalyserHz );
79 |
--------------------------------------------------------------------------------
/gsuiAnalyserVu/gsuiAnalyserVu.css:
--------------------------------------------------------------------------------
1 | gsui-analyser-vu {
2 | display: flex;
3 | gap: min( max( 5%, 1px ), 8px );
4 | height: 100%;
5 | }
6 |
7 | .gsuiAnalyserVu-meter {
8 | position: relative;
9 | flex: 1;
10 | height: 100%;
11 | background-color: var( --gsui-screen-spectrum );
12 | filter: var( --gsui-screen-spectrum-filter );
13 | }
14 |
15 | .gsuiAnalyserVu-meter-val {
16 | position: absolute;
17 | inset: auto 0 0;
18 | background-color: #ff9;
19 | }
20 | .gsuiAnalyserVu-meter-val-max {
21 | position: absolute;
22 | inset: 0 0 auto 0;
23 | background-color: #e04c4c;
24 | }
25 |
26 | .gsuiAnalyserVu-meter-tick,
27 | .gsuiAnalyserVu-meter-0dB {
28 | position: absolute;
29 | width: 100%;
30 | height: 2px;
31 | margin-bottom: -2px;
32 | background-color: #fff;
33 | }
34 | .gsuiAnalyserVu-meter-tick {
35 | bottom: 0;
36 | opacity: 0;
37 | transition: opacity .4s;
38 | }
39 | .gsuiAnalyserVu-meter-0dB {
40 | opacity: .1;
41 | }
42 |
--------------------------------------------------------------------------------
/gsuiAnalyserVu/gsuiAnalyserVu.html.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | GSUsetTemplate( "gsui-analyser-vu", () => [
4 | GSUgetTemplate( "gsui-analyser-vu-meter", { chan: "L" } ),
5 | GSUgetTemplate( "gsui-analyser-vu-meter", { chan: "R" } ),
6 | ] );
7 |
8 | GSUsetTemplate( "gsui-analyser-vu-meter", p =>
9 | GSUcreateDiv( { class: "gsuiAnalyserVu-meter", "data-chan": p.chan, inert: true },
10 | GSUcreateDiv( { class: "gsuiAnalyserVu-meter-val" },
11 | GSUcreateDiv( { class: "gsuiAnalyserVu-meter-val-max" } ),
12 | ),
13 | GSUcreateDiv( { class: "gsuiAnalyserVu-meter-tick" } ),
14 | GSUcreateDiv( { class: "gsuiAnalyserVu-meter-0dB" } ),
15 | ),
16 | );
17 |
--------------------------------------------------------------------------------
/gsuiBeatlines/gsuiBeatlines.css:
--------------------------------------------------------------------------------
1 | gsui-beatlines {
2 | --gsui-deg: 90deg;
3 | --gsui-bPM: 4em;
4 | --gsui-sPB: .25em;
5 | position: absolute;
6 | inset: 0;
7 | pointer-events: none;
8 | color: var( --gsuiBeatlines-lines, #000 );
9 | }
10 | gsui-beatlines[ vertical ] {
11 | --gsui-deg: 180deg;
12 | }
13 |
14 | /* .......................................................................... */
15 | .gsuiBeatlines-bg {
16 | position: absolute;
17 | inset: 0;
18 | }
19 | .gsuiBeatlines-measures {
20 | background-image: repeating-linear-gradient(
21 | var( --gsui-deg ),
22 | currentColor,
23 | currentColor 1px,
24 | transparent 1px,
25 | transparent calc( var( --gsui-bPM ) - 1px ),
26 | currentColor calc( var( --gsui-bPM ) - 1px ),
27 | currentColor var( --gsui-bPM ) );
28 | }
29 | .gsuiBeatlines-steps {
30 | opacity: .2;
31 | background-image: repeating-linear-gradient(
32 | var( --gsui-deg ),
33 | currentColor,
34 | currentColor .5px,
35 | transparent .5px,
36 | transparent calc( var( --gsui-sPB ) - .5px ),
37 | currentColor calc( var( --gsui-sPB ) - .5px ),
38 | currentColor var( --gsui-sPB ) );
39 | }
40 | .gsuiBeatlines-beats {
41 | opacity: .75;
42 | background-image: repeating-linear-gradient(
43 | var( --gsui-deg ),
44 | currentColor,
45 | currentColor .5px,
46 | transparent .5px,
47 | transparent calc( 1em - .5px ),
48 | currentColor calc( 1em - .5px ),
49 | currentColor 1em );
50 | }
51 | gsui-beatlines[ coloredbeats ] .gsuiBeatlines-beatsBG {
52 | background-image: repeating-linear-gradient(
53 | var( --gsui-deg ),
54 | #0001,
55 | #0001 1em,
56 | transparent 1em,
57 | transparent 2em );
58 | }
59 |
--------------------------------------------------------------------------------
/gsuiBeatlines/gsuiBeatlines.html.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | GSUsetTemplate( "gsui-beatlines", () => [
4 | GSUcreateDiv( { class: "gsuiBeatlines-bg gsuiBeatlines-measures" } ),
5 | GSUcreateDiv( { class: "gsuiBeatlines-bg gsuiBeatlines-beats" } ),
6 | GSUcreateDiv( { class: "gsuiBeatlines-bg gsuiBeatlines-steps" } ),
7 | GSUcreateDiv( { class: "gsuiBeatlines-bg gsuiBeatlines-beatsBG" } ),
8 | ] );
9 |
--------------------------------------------------------------------------------
/gsuiBeatlines/gsuiBeatlines.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | class gsuiBeatlines extends gsui0ne {
4 | constructor() {
5 | super( {
6 | $cmpName: "gsuiBeatlines",
7 | $tagName: "gsui-beatlines",
8 | $attributes: {
9 | timedivision: "4/4",
10 | coloredbeats: true,
11 | pxperbeat: 10,
12 | },
13 | } );
14 | }
15 | static get observedAttributes() {
16 | return [ "timedivision", "pxperbeat" ];
17 | }
18 | $attributeChanged( prop, val ) {
19 | switch ( prop ) {
20 | case "timedivision":
21 | GSUsetStyle( this, {
22 | "--gsui-bPM": `${ val.split( "/" )[ 0 ] }em`,
23 | "--gsui-sPB": `${ 1 / val.split( "/" )[ 1 ] }em`,
24 | } );
25 | break;
26 | case "pxperbeat":
27 | GSUsetStyle( this, {
28 | fontSize: `${ val }px`,
29 | opacity: Math.min( val / 48, 1 ),
30 | } );
31 | break;
32 | }
33 | }
34 | }
35 |
36 | GSUdefineElement( "gsui-beatlines", gsuiBeatlines );
37 |
--------------------------------------------------------------------------------
/gsuiBlocksManager/gsuiBlocksManager.css:
--------------------------------------------------------------------------------
1 | .gsuiBlocksManager {
2 | --gsuiBlocksManager-timeline-height: 32px;
3 | --gsuiBlocksManager-selection-bgColor: #b226;
4 | --gsuiBlocksManager-selection-borderColor: #f44;
5 | --gsuiBlocksManager-blockColor: var( --gsui-col-pattern8 );
6 | --gsuiBlocksManager-blockSelectedColor: var( --gsui-col-patternSelected8 );
7 | }
8 |
9 | /* .......................................................................... */
10 | .gsuiBlocksManager-selection {
11 | position: absolute;
12 | box-sizing: border-box;
13 | top: 0;
14 | z-index: 2;
15 | border: 2px solid var( --gsuiBlocksManager-selection-borderColor );
16 | border-radius: 4px;
17 | background-color: var( --gsuiBlocksManager-selection-bgColor );
18 | transition: .2s;
19 | transition-property: opacity, visibility;
20 | }
21 | .gsuiBlocksManager-selection-hidden {
22 | opacity: 0;
23 | visibility: hidden;
24 | }
25 |
26 | /* .......................................................................... */
27 | .gsuiBlocksManager-block {
28 | position: absolute;
29 | z-index: 1;
30 | top: 0;
31 | bottom: 1px;
32 | background-color: var( --gsuiBlocksManager-blockColor );
33 | transition: .1s;
34 | transition-property: opacity, background-color;
35 | }
36 | .gsuiBlocksManager-block-selected {
37 | --gsuiBlocksManager-blockColor: var( --gsuiBlocksManager-blockSelectedColor );
38 | }
39 | .gsuiBlocksManager-block-hidden.gsuiBlocksManager-block-hidden.gsuiBlocksManager-block-hidden {
40 | z-index: 0;
41 | opacity: .3;
42 | }
43 | .gsuiBlocksManager-block-crop {
44 | position: absolute;
45 | z-index: 2;
46 | width: 50%;
47 | height: 100%;
48 | max-width: 8px;
49 | border-radius: inherit;
50 | background-color: #000;
51 | opacity: 0;
52 | transition: .1s opacity;
53 | }
54 | .gsuiBlocksManager-block-cropA {
55 | left: 0;
56 | border-top-right-radius: 0;
57 | border-bottom-right-radius: 0;
58 | }
59 | .gsuiBlocksManager-block-cropB {
60 | right: 0;
61 | border-top-left-radius: 0;
62 | border-bottom-left-radius: 0;
63 | }
64 | .gsuiBlocksManager-block:hover .gsuiBlocksManager-block-crop,
65 | .gsuiBlocksManager-block.gsui-hover .gsuiBlocksManager-block-crop {
66 | opacity: .12;
67 | }
68 | .gsuiBlocksManager-block .gsuiBlocksManager-block-crop:hover,
69 | .gsuiBlocksManager-block .gsuiBlocksManager-block-crop.gsui-hover {
70 | opacity: .25;
71 | }
72 |
--------------------------------------------------------------------------------
/gsuiChannel/gsuiChannel.html.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | GSUsetTemplate( "gsui-channel", () => [
4 | GSUcreateButton( { class: "gsuiChannel-nameWrap" },
5 | GSUcreateSpan( { class: "gsuiChannel-name" } ),
6 | ),
7 | GSUcreateButton( { class: "gsuiChannel-headBtn gsuiChannel-rename", icon: "pen", title: "Rename the channel" } ),
8 | GSUcreateButton( { class: "gsuiChannel-headBtn gsuiChannel-delete", icon: "close", title: "Remove the channel" } ),
9 | GSUcreateDiv( { class: "gsuiChannel-analyser" },
10 | GSUcreateElement( "gsui-analyser-hist" ),
11 | GSUcreateDiv( { class: "gsuiChannel-effects" } ),
12 | ),
13 | GSUcreateElement( "gsui-toggle" ),
14 | GSUcreateDiv( { class: "gsuiChannel-pan" },
15 | GSUcreateElement( "gsui-slider", { type: "circular", min: -1, max: 1, step: .02, "mousemove-size": 800, "stroke-width": 3, "data-prop": "pan", defaultValue: 0 } ),
16 | ),
17 | GSUcreateDiv( { class: "gsuiChannel-gain" },
18 | GSUcreateElement( "gsui-slider", { type: "linear-y", min: 0, max: 1, step: .01, "mousemove-size": 400, "data-prop": "gain", defaultValue: 1 } ),
19 | ),
20 | GSUcreateButton( { class: "gsuiChannel-connect" },
21 | GSUcreateIcon( { class: "gsuiChannel-connectA", icon: "caret-up" } ),
22 | GSUcreateIcon( { class: "gsuiChannel-connectB", icon: "caret-up" } ),
23 | ),
24 | GSUcreateDiv( { class: "gsuiChannel-grip gsuiIcon", "data-icon": "grip-h" } ),
25 | ] );
26 |
27 | GSUsetTemplate( "gsui-channel-effect", ( id, name ) =>
28 | GSUcreateButton( { class: "gsuiChannel-effect gsuiChannel-effect-enable", "data-id": id },
29 | GSUcreateSpan( { class: "gsuiChannel-effect-name" }, name ),
30 | ),
31 | );
32 |
--------------------------------------------------------------------------------
/gsuiChannel/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/gsuiChannels/gsuiChannels.css:
--------------------------------------------------------------------------------
1 | gsui-channels {
2 | --vuW: 11px;
3 | display: flex;
4 | z-index: 0;
5 | height: 100%;
6 | position: relative;
7 | background-color: var( --gsui-items-bg );
8 | }
9 |
10 | gsui-channels gsui-analyser-vu {
11 | width: var( --vuW );
12 | }
13 |
14 | /* .......................................................................... */
15 | .gsuiChannels-panMain {
16 | position: absolute;
17 | inset: 0 auto 0 0;
18 | display: flex;
19 | gap: 3px;
20 | }
21 | .gsuiChannels-panChannels {
22 | position: absolute;
23 | overflow: scroll;
24 | inset: 0 0 0 calc( var( --vuW ) + 3px + 50px );
25 | display: flex;
26 | scrollbar-width: none;
27 | }
28 | .gsuiChannels-panChannels::-webkit-scrollbar {
29 | display: none;
30 | }
31 | .gsuiChannels-panChannels::after {
32 | order: 2147483647;
33 | content: ".";
34 | opacity: 0;
35 | margin-left: 16px;
36 | }
37 |
38 | /* .......................................................................... */
39 | .gsuiChannels-addChan {
40 | position: relative;
41 | order: 2147483646;
42 | display: flex;
43 | flex-direction: column;
44 | gap: 1ch;
45 | align-items: center;
46 | justify-content: center;
47 | min-width: 52px;
48 | border: 0;
49 | padding: 0;
50 | outline: 0;
51 | font-size: 18px;
52 | color: inherit;
53 | cursor: pointer;
54 | border-radius: 2px;
55 | background: none;
56 | opacity: .4;
57 | transition: .2s opacity;
58 | }
59 | .gsuiChannels-addChan:focus,
60 | .gsuiChannels-addChan:hover {
61 | opacity: .6;
62 | }
63 | .gsuiChannels-addChan::before {
64 | content: "";
65 | inset: 6px;
66 | opacity: .4;
67 | border: 2px dashed;
68 | position: absolute;
69 | }
70 | .gsuiChannels-addChan .gsuiIcon:first-child {
71 | font-size: 24px;
72 | }
73 | .gsuiChannels-addChan .gsuiIcon:last-child {
74 | font-size: 14px;
75 | }
76 |
--------------------------------------------------------------------------------
/gsuiChannels/gsuiChannels.html.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | GSUsetTemplate( "gsui-channels", () => [
4 | GSUcreateDiv( { class: "gsuiChannels-panMain" },
5 | GSUcreateElement( "gsui-analyser-vu", { max: 120, title: "current channel's VU (max 120%)" } ),
6 | ),
7 | GSUcreateDiv( { class: "gsuiChannels-panChannels" },
8 | GSUcreateButton( { class: "gsuiChannels-addChan", title: "Add a channel" },
9 | GSUcreateIcon( { icon: "channels" } ),
10 | GSUcreateIcon( { icon: "plus" } ),
11 | ),
12 | ),
13 | ] );
14 |
15 | GSUsetTemplate( "gsui-channels-selectPopup", () =>
16 | GSUcreateDiv( null,
17 | GSUcreateElement( "fieldset", null,
18 | GSUcreateElement( "legend", null, "Select a channel" ),
19 | GSUcreateSelect( { name: "channel", size: 8 } ),
20 | ),
21 | )
22 | );
23 |
--------------------------------------------------------------------------------
/gsuiClock/gsuiClock.css:
--------------------------------------------------------------------------------
1 | gsui-clock {
2 | display: flex;
3 | width: min-content;
4 | height: 28px;
5 | min-height: 28px;
6 | border-radius: 4px;
7 | font-size: 18px;
8 | background-color: var( --gsui-clock-bg );
9 | }
10 |
11 | .gsuiClock-relative {
12 | position: relative;
13 | height: 100%;
14 | padding-left: 8px;
15 | border-top-left-radius: inherit;
16 | border-bottom-left-radius: inherit;
17 | }
18 | .gsuiClock-absolute {
19 | display: flex;
20 | position: absolute;
21 | white-space: nowrap;
22 | align-items: baseline;
23 | padding-top: 4px;
24 | font-family: var( --gsui-font-number );
25 | }
26 |
27 | .gsuiClock-modes {
28 | position: relative;
29 | display: flex;
30 | margin: 0;
31 | border: 0;
32 | outline: 0;
33 | padding: 7px 6px;
34 | border-top-right-radius: inherit;
35 | border-bottom-right-radius: inherit;
36 | cursor: pointer;
37 | color: inherit;
38 | flex-direction: column;
39 | justify-content: space-between;
40 | background: none;
41 | }
42 | .gsuiClock-modes:focus-visible {
43 | box-shadow: 0 0 1px 2px #69b;
44 | }
45 | .gsuiClock-mode {
46 | width: 5px;
47 | height: 5px;
48 | border-radius: 1px;
49 | background-color: currentColor;
50 | opacity: .2;
51 | }
52 | gsui-clock[ mode="beat" ] .gsuiClock-beat,
53 | gsui-clock[ mode="second" ] .gsuiClock-second {
54 | opacity: .8;
55 | }
56 |
57 | .gsuiClock-b::before {
58 | content: ":";
59 | margin: 0 .2ch;
60 | }
61 | .gsuiClock-c {
62 | font-size: 12px;
63 | opacity: .5;
64 | }
65 | .gsuiClock-c::before {
66 | content: ".";
67 | margin: 0 .4ch;
68 | }
69 |
70 | .gsuiClock-modeText {
71 | position: absolute;
72 | top: 3px;
73 | right: 0;
74 | font-size: 8px;
75 | font-family: var( --gsui-font );
76 | opacity: .25;
77 | }
78 | gsui-clock[ mode="beat" ] .gsuiClock-modeText::before { content: "beat"; }
79 | gsui-clock[ mode="second" ] .gsuiClock-modeText::before { content: "sec"; }
80 |
--------------------------------------------------------------------------------
/gsuiClock/gsuiClock.html.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | GSUsetTemplate( "gsui-clock", () => [
4 | GSUcreateDiv( { class: "gsuiClock-relative", inert: true },
5 | GSUcreateDiv( { class: "gsuiClock-absolute" },
6 | GSUcreateDiv( { class: "gsuiClock-a" }, "0" ),
7 | GSUcreateDiv( { class: "gsuiClock-b" }, "00" ),
8 | GSUcreateDiv( { class: "gsuiClock-c" }, "000" ),
9 | GSUcreateSpan( { class: "gsuiClock-modeText" } ),
10 | ),
11 | ),
12 | GSUcreateButton( { class: "gsuiClock-modes" },
13 | GSUcreateDiv( { class: "gsuiClock-mode gsuiClock-beat" } ),
14 | GSUcreateDiv( { class: "gsuiClock-mode gsuiClock-second" } ),
15 | )
16 | ] );
17 |
--------------------------------------------------------------------------------
/gsuiClock/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/gsuiComAvatar/gsuiComAvatar.css:
--------------------------------------------------------------------------------
1 | gsui-com-avatar {
2 | container-type: inline-size;
3 | overflow: hidden;
4 | display: flex;
5 | align-items: center;
6 | justify-content: center;
7 | min-width: 24px;
8 | min-height: 24px;
9 | background-color: #0001;
10 | }
11 |
12 | gsui-com-avatar img {
13 | width: 100%;
14 | height: 100%;
15 | object-fit: cover;
16 | }
17 | gsui-com-avatar .gsuiIcon {
18 | position: absolute;
19 | font-size: 60cqw;
20 | color: #2e355b;
21 | }
22 |
23 | gsui-com-avatar:not( [ loaded ] ) img,
24 | gsui-com-avatar[ loaded ] .gsuiIcon {
25 | display: none;
26 | }
27 |
--------------------------------------------------------------------------------
/gsuiComAvatar/gsuiComAvatar.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | class gsuiComAvatar extends gsui0ne {
4 | constructor() {
5 | super( {
6 | $cmpName: "gsuiComAvatar",
7 | $tagName: "gsui-com-avatar",
8 | $template: [
9 | GSUcreateElement( "img", { src: "" } ),
10 | GSUcreateIcon( { icon: "musician" } ),
11 | ],
12 | } );
13 | Object.seal( this );
14 | this.$element.onload = () => GSUsetAttribute( this, "loaded", true );
15 | }
16 |
17 | // .........................................................................
18 | static get observedAttributes() {
19 | return [ "src" ];
20 | }
21 | $attributeChanged( prop, val ) {
22 | switch ( prop ) {
23 | case "src":
24 | GSUsetAttribute( this, "loaded", false );
25 | this.$element.src = val || "";
26 | break;
27 | }
28 | }
29 | }
30 |
31 | GSUdefineElement( "gsui-com-avatar", gsuiComAvatar );
32 |
--------------------------------------------------------------------------------
/gsuiComAvatar/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/gsuiComButton/gsuiComButton.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | class gsuiComButton extends gsui0ne {
4 | #href = null;
5 |
6 | constructor() {
7 | super( {
8 | $cmpName: "gsuiComButton",
9 | $tagName: "gsui-com-button",
10 | $template: GSUcreateButton( { class: "gsuiComButton-btn" },
11 | GSUcreateSpan( { class: "gsuiComButton-text" } ),
12 | ),
13 | } );
14 | Object.seal( this );
15 | gsuiRipple.$init( this.$element );
16 | this.$element.addEventListener( "click", () => {
17 | if ( GSUhasAttribute( this, "href" ) ) {
18 | window.location = this.#href;
19 | }
20 | } );
21 | }
22 |
23 | // .........................................................................
24 | static get observedAttributes() {
25 | return [ "text", "loading", "disabled", "type", "href" ];
26 | }
27 | $attributeChanged( prop, val ) {
28 | switch ( prop ) {
29 | case "disabled":
30 | case "loading": this.#updateDisabled(); break;
31 | case "text": this.$element.firstChild.textContent = val; break;
32 | case "type": this.$element.type = val === "submit" ? val : "button"; break;
33 | case "href": this.#href = val; break;
34 | }
35 | }
36 |
37 | // .........................................................................
38 | #updateDisabled() {
39 | this.$element.disabled = GSUhasAttribute( this, "disabled" ) || GSUhasAttribute( this, "loading" );
40 | }
41 | }
42 |
43 | GSUdefineElement( "gsui-com-button", gsuiComButton );
44 |
--------------------------------------------------------------------------------
/gsuiComButton/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
71 |
72 |
73 |
--------------------------------------------------------------------------------
/gsuiComPlayer/gsuiComPlayer.html.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | GSUsetTemplate( "gsui-com-player", () => [
4 | GSUcreateButton( { class: "gsuiComPlayer-btn gsuiComPlayer-play", icon: "play" } ),
5 | GSUcreateDiv( { class: "gsuiComPlayer-body" },
6 | GSUcreateDiv( { class: "gsuiComPlayer-text" },
7 | GSUcreateDiv( { class: "gsuiComPlayer-name" },
8 | GSUcreateA( { class: "gsuiComPlayer-nameLink", href: false } ),
9 | ),
10 | GSUcreateDiv( { class: "gsuiComPlayer-info-wrap" },
11 | GSUcreateDiv( { class: "gsuiComPlayer-info" },
12 | GSUcreateDiv( { class: "gsuiComPlayer-time" },
13 | GSUcreateIcon( { icon: "clock" } ),
14 | GSUcreateSpan( { class: "gsuiComPlayer-currentTime" } ),
15 | GSUcreateSpan( { class: "gsuiComPlayer-duration" } ),
16 | ),
17 | GSUcreateDiv( { class: "gsuiComPlayer-tempo" },
18 | GSUcreateIcon( { icon: "speed" } ),
19 | GSUcreateSpan( { class: "gsuiComPlayer-bpm" } ),
20 | ),
21 | ),
22 | ),
23 | ),
24 | GSUcreateDiv( { class: "gsuiComPlayer-slider" },
25 | GSUcreateDiv( { class: "gsuiComPlayer-sliderValue" } ),
26 | GSUcreateDiv( { class: "gsuiComPlayer-sliderInput" } ),
27 | ),
28 | ),
29 | GSUcreateAExt( { class: "gsuiComPlayer-btn gsuiComPlayer-dawlink", title: "Open in the DAW", href: false },
30 | GSUcreateIcon( { icon: "music" } ),
31 | GSUcreateIcon( { icon: "pen" } ),
32 | GSUcreateIcon( { icon: "eye" } ),
33 | ),
34 | GSUcreateButton( { class: "gsuiComPlayer-btn gsuiComPlayer-actions", icon: "ellipsis-v" } ),
35 | ] );
36 |
--------------------------------------------------------------------------------
/gsuiComPlaylist/gsuiComPlaylist.html.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | GSUsetTemplate( "gsui-com-playlist", () => [
4 | GSUcreateDiv( { class: "gsuiComPlaylist-head" },
5 | GSUcreateButton( { class: "gsuiComPlaylist-head-btn" },
6 | GSUcreateSpan(),
7 | GSUcreateSpan( null, "composition·s" ),
8 | ),
9 | GSUcreateButton( { class: "gsuiComPlaylist-head-btn" },
10 | GSUcreateSpan(),
11 | GSUcreateSpan( null, "in the bin" ),
12 | ),
13 | ),
14 | GSUcreateDiv( { class: "gsuiComPlaylist-list", "data-list": "cmps" } ),
15 | GSUcreateDiv( { class: "gsuiComPlaylist-list", "data-list": "bin" } ),
16 | GSUcreateDiv( { class: "gsuiComPlaylist-placeh", "data-list": "cmps" },
17 | GSUcreateSpan( { class: "gsuiComPlaylist-placeh-text" },
18 | GSUcreateSpan( null, "No saved composition yet" ),
19 | GSUcreateSpan( null, ", you should create a new one right now!" ),
20 | ),
21 | GSUcreateDiv( { class: "gsuiComPlaylist-placeh-draw" },
22 | GSUcreateIcon( { icon: "music" } ),
23 | ),
24 | ),
25 | GSUcreateDiv( { class: "gsuiComPlaylist-placeh", "data-list": "bin" },
26 | GSUcreateSpan( { class: "gsuiComPlaylist-placeh-text" }, "There is no composition inside your bin." ),
27 | GSUcreateDiv( { class: "gsuiComPlaylist-placeh-draw" },
28 | GSUcreateIcon( { icon: "trash" } ),
29 | ),
30 | ),
31 | ] );
32 |
--------------------------------------------------------------------------------
/gsuiCurves/gsuiCurves.css:
--------------------------------------------------------------------------------
1 | gsui-curves {
2 | display: flex;
3 | flex-direction: column;
4 | gap: 4px;
5 | height: 100%;
6 | }
7 |
8 | /* .......................................................................... */
9 | .gsuiCurves-marks {
10 | display: flex;
11 | align-items: center;
12 | height: 10px;
13 | }
14 | .gsuiCurves-marks div {
15 | flex: 1;
16 | font-size: 10px;
17 | }
18 | .gsuiCurves-marks div::before {
19 | content: attr( data-hz );
20 | display: flex;
21 | padding-left: 3px;
22 | margin-right: 3px;
23 | opacity: .2;
24 | background-color: #000;
25 | }
26 | .gsuiCurves-marks div:last-child::before {
27 | margin-right: 0;
28 | }
29 |
30 | /* .......................................................................... */
31 | .gsuiCurves-graph {
32 | flex: 1;
33 | position: relative;
34 | overflow: hidden;
35 | border-radius: 4px;
36 | }
37 |
38 | /* .......................................................................... */
39 | gsui-curves gsui-analyser-hz {
40 | position: absolute;
41 | inset: 0;
42 | background-color: var( --gsui-screen-graph );
43 | }
44 |
45 | /* .......................................................................... */
46 | .gsuiCurves-svg {
47 | position: absolute;
48 | width: 100%;
49 | height: 100%;
50 | }
51 | .gsuiCurves-line {
52 | stroke: currentColor;
53 | stroke-width: 2;
54 | stroke-dasharray: 4;
55 | opacity: .5;
56 | }
57 | .gsuiCurves-curve {
58 | fill: none;
59 | stroke: currentColor;
60 | stroke-width: 3;
61 | filter: drop-shadow( 0 -1px 0 #000a ) drop-shadow( 0 1px 0 #000a );
62 | }
63 |
--------------------------------------------------------------------------------
/gsuiCurves/gsuiCurves.html.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | GSUsetTemplate( "gsui-curves", () => [
4 | GSUcreateDiv( { class: "gsuiCurves-marks" } ),
5 | GSUcreateDiv( { class: "gsuiCurves-graph" },
6 | GSUcreateElement( "gsui-analyser-hz" ),
7 | GSUcreateElementSVG( "svg", { class: "gsuiCurves-svg", preserveAspectRatio: "none" },
8 | GSUcreateElementSVG( "line", { class: "gsuiCurves-line", "shape-rendering": "crispEdges" } ),
9 | GSUcreateElementSVG( "g", { class: "gsuiCurves-curves" } ),
10 | )
11 | )
12 | ] );
13 |
--------------------------------------------------------------------------------
/gsuiDAW/gsuiDAW-btn.css:
--------------------------------------------------------------------------------
1 | .gsuiDAW-btn {
2 | display: inline-flex;
3 | align-items: center;
4 | justify-content: center;
5 | border: 0;
6 | padding: 0;
7 | outline: 0;
8 | color: inherit;
9 | cursor: pointer;
10 | font-size: 14px;
11 | line-height: 28px;
12 | text-decoration: none;
13 | border-radius: var( --radius );
14 | background: none;
15 | transition: .2s;
16 | transition-property: color, opacity, background-color;
17 | }
18 | .gsuiDAW-btn.gsuiIcon {
19 | width: 28px;
20 | }
21 | .gsuiDAW-btn:not( .gsuiDAW-btnColor ):hover {
22 | color: #fff;
23 | opacity: 1;
24 | }
25 | .gsuiDAW-btn:active {
26 | padding-top: 4px;
27 | }
28 |
29 | .gsuiDAW-btnBg {
30 | background-color: var( --gsui-btn-default-bg );
31 | }
32 | .gsuiDAW-btnBg:hover {
33 | background-color: #fff3;
34 | }
35 |
36 | .gsuiDAW-btnColor {
37 | color: var( --gsui-color );
38 | }
39 | .gsuiDAW-btnColor:hover {
40 | color: var( --gsui-head1-bg );
41 | background-color: var( --gsui-color );
42 | }
43 |
44 | .gsuiDAW-btns {
45 | display: flex;
46 | border-radius: var( --radius );
47 | }
48 | .gsuiDAW-btns .gsuiDAW-btn:first-child {
49 | border-top-right-radius: 0;
50 | border-bottom-right-radius: 0;
51 | }
52 | .gsuiDAW-btns .gsuiDAW-btn:last-child {
53 | border-top-left-radius: 0;
54 | border-bottom-left-radius: 0;
55 | }
56 | .gsuiDAW-btns .gsuiDAW-btn:not( :first-child ):not( :last-child ) {
57 | border-radius: 0;
58 | }
59 |
--------------------------------------------------------------------------------
/gsuiDAW/gsuiDAW-popup-about.css:
--------------------------------------------------------------------------------
1 | .gsuiDAW-popup-about {
2 | width: 450px;
3 | text-align: center;
4 | }
5 |
6 | /* .......................................................................... */
7 | .gsuiDAW-popup-about > div {
8 | margin-bottom: 16px;
9 | }
10 | .gsuiDAW-popup-about a {
11 | color: #ccf;
12 | font-weight: bold;
13 | }
14 |
15 | /* .......................................................................... */
16 | .gsuiDAW-popup-about-head {
17 | display: flex;
18 | align-items: baseline;
19 | justify-content: center;
20 | font-size: 18px;
21 | gap: 4px;
22 | }
23 | .gsuiDAW-popup-about-title {
24 | font: 32px var( --gsui-font-title );
25 | }
26 | .gsuiDAW-popup-about-versionNum {
27 | opacity: .8;
28 | font-family: var( --gsui-font-number );
29 | }
30 | .gsuiDAW-popup-about-versionCheck {
31 | font-size: 11px;
32 | font-weight: bold;
33 | opacity: .4;
34 | cursor: pointer;
35 | transition: .2s opacity;
36 | }
37 | .gsuiDAW-popup-about-versionCheck:hover {
38 | opacity: 1;
39 | }
40 |
41 | /* .......................................................................... */
42 | .gsuiDAW-popup-about-links {
43 | display: flex;
44 | }
45 | .gsuiDAW-popup-about-links a {
46 | flex: 1;
47 | padding: 20px 0;
48 | color: #fff;
49 | font-size: 36px;
50 | font-weight: normal;
51 | opacity: .5;
52 | transition: .4s;
53 | transition-property: opacity;
54 | }
55 | .gsuiDAW-popup-about-links a:hover {
56 | opacity: 1;
57 | }
58 | .gsuiDAW-popup-about-links a:hover::before {
59 | top: -4px;
60 | left: 4px;
61 | text-shadow: -4px 4px 2px rgba( 0, 0, 0, .2 );
62 | }
63 | .gsuiDAW-popup-about-links a::before {
64 | position: relative;
65 | top: 0;
66 | left: 0;
67 | transition: .2s;
68 | transition-property: top, left, text-shadow;
69 | }
70 | .gsuiDAW-popup-about-links:hover a:not( :hover ) {
71 | opacity: .3;
72 | }
73 |
--------------------------------------------------------------------------------
/gsuiDAW/gsuiDAW-popup-about.html.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | GSUsetTemplate( "gsui-daw-popup-about", () =>
4 | GSUcreateDiv( { class: "gsuiDAW-popup-about" },
5 | GSUcreateDiv( { class: "gsuiDAW-popup-about-head" },
6 | GSUcreateSpan( { class: "gsuiDAW-popup-about-title" }, "GridSound" ),
7 | GSUcreateSpan( { class: "gsuiDAW-popup-about-versionNum" } ),
8 | GSUcreateIcon( null ),
9 | GSUcreateButton( { class: "gsuiDAW-popup-about-versionCheck" }, "check the version" ),
10 | ),
11 | GSUcreateDiv( null,
12 | "GridSound is a ",
13 | GSUcreateElement( "b", null, "work-in-progress" ),
14 | " free browser-based digital audio workstation following the ",
15 | GSUcreateAExt( { href: "https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API" }, "Web Audio API" ),
16 | ".",
17 | ),
18 | GSUcreateDiv( null,
19 | "You can create an account (by clicking ", GSUcreateIcon( { icon: "profile" } ),
20 | ") and start uploading your compositions online ", GSUcreateIcon( { icon: "cloud" } ),
21 | ),
22 | GSUcreateDiv( { class: "gsuiDAW-popup-about-links" },
23 | GSUcreateAExt( { title: "GitHub", class: "gsuiIcon", "data-icon": "br-github", href: "https://github.com/gridsound" } ),
24 | GSUcreateAExt( { title: "Twitter", class: "gsuiIcon", "data-icon": "br-twitter", href: "https://twitter.com/gridsound" } ),
25 | GSUcreateAExt( { title: "YouTube", class: "gsuiIcon", "data-icon": "br-youtube", href: "https://youtube.com/@gridsound" } ),
26 | GSUcreateAExt( { title: "Facebook", class: "gsuiIcon", "data-icon": "br-facebook", href: "https://facebook.com/gridsound" } ),
27 | GSUcreateAExt( { title: "CodePen", class: "gsuiIcon", "data-icon": "br-codepen", href: "https://codepen.io/gridsound" } ),
28 | GSUcreateAExt( { title: "Discord", class: "gsuiIcon", "data-icon": "br-discord", href: "https://discord.gg/NUYxHAg" } ),
29 | ),
30 | )
31 | );
32 |
--------------------------------------------------------------------------------
/gsuiDAW/gsuiDAW-popup-export.css:
--------------------------------------------------------------------------------
1 | .gsuiDAW-popup-export {
2 | width: 500px;
3 | }
4 | .gsuiDAW-popup-export-wrap {
5 | display: flex;
6 | padding: 10px 0;
7 | }
8 | .gsuiDAW-popup-export-progress {
9 | flex: 1;
10 | height: 28px;
11 | }
12 | .gsuiDAW-popup-export-btn {
13 | padding: 0 .8em;
14 | border-radius: 2px;
15 | margin-right: 10px;
16 | font-size: 12px;
17 | line-height: 28px;
18 | font-weight: bold;
19 | text-decoration: none;
20 | background-color: #ff9;
21 | }
22 | .gsuiDAW-popup-export-btn > span {
23 | display: none;
24 | color: #111;
25 | }
26 | .gsuiDAW-popup-export-btn[ data-status="0" ] .gsuiDAW-popup-export-btn0,
27 | .gsuiDAW-popup-export-btn[ data-status="1" ] .gsuiDAW-popup-export-btn1,
28 | .gsuiDAW-popup-export-btn[ data-status="2" ] .gsuiDAW-popup-export-btn2 {
29 | display: inline;
30 | }
31 | .gsuiDAW-popup-export-btn .gsuiIcon {
32 | margin-left: .3em;
33 | }
34 |
--------------------------------------------------------------------------------
/gsuiDAW/gsuiDAW-popup-export.html.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | GSUsetTemplate( "gsui-daw-popup-export", () =>
4 | GSUcreateDiv( { class: "gsuiDAW-popup-export" },
5 | GSUcreateElement( "fieldset", null,
6 | GSUcreateElement( "legend", null, "Render the current composition" ),
7 | GSUcreateDiv( { class: "gsuiDAW-popup-export-wrap" },
8 | GSUcreateA( { class: "gsuiDAW-popup-export-btn", "data-status": 0 },
9 | GSUcreateSpan( { class: "gsuiDAW-popup-export-btn0" },
10 | GSUcreateSpan( null, "Render" ),
11 | GSUcreateIcon( { icon: "render" } ),
12 | ),
13 | GSUcreateSpan( { class: "gsuiDAW-popup-export-btn1" },
14 | GSUcreateSpan( null, "Rendering..." ),
15 | GSUcreateIcon( { spin: true } ),
16 | ),
17 | GSUcreateSpan( { class: "gsuiDAW-popup-export-btn2" },
18 | GSUcreateSpan( null, "Download WAV file" ),
19 | GSUcreateIcon( { icon: "export" } ),
20 | ),
21 | ),
22 | GSUcreateElement( "progress", { class: "gsuiDAW-popup-export-progress", value: "", max: 1 } ),
23 | ),
24 | ),
25 | )
26 | );
27 |
--------------------------------------------------------------------------------
/gsuiDAW/gsuiDAW-popup-settings.css:
--------------------------------------------------------------------------------
1 | .gsuiDAW-popup-settings {
2 | width: 480px;
3 | }
4 | .gsuiDAW-popup-settings .gsuiPopup-row-values {
5 | width: 200px;
6 | }
7 | .gsuiDAW-uiRateFps {
8 | font-size: 16px;
9 | font-family: var( --gsui-font-number );
10 | white-space: pre;
11 | }
12 | .gsuiDAW-uiRateFps::after {
13 | content: " fps";
14 | font-family: var( --gsui-font );
15 | font-size: 12px;
16 | opacity: .6;
17 | }
18 | .gsuiDAW-popup-settings input[ name="uiRateFPS" ] {
19 | min-width: 0;
20 | }
21 |
--------------------------------------------------------------------------------
/gsuiDAW/gsuiDAW-windows.css:
--------------------------------------------------------------------------------
1 | .gsuiDAW-winBtn {
2 | height: 16px;
3 | padding: 0 6px;
4 | max-width: 110px;
5 | border: 0;
6 | outline: 0;
7 | cursor: pointer;
8 | overflow: hidden;
9 | border-radius: 3px;
10 | line-height: 1;
11 | color: inherit;
12 | font-size: 10px;
13 | font-weight: bold;
14 | font-family: inherit;
15 | white-space: nowrap;
16 | text-overflow: ellipsis;
17 | background-color: var( --gsuiDAW-winBtn-bg );
18 | transition: filter .2s;
19 | }
20 | .gsuiDAW-winBtn:focus,
21 | .gsuiDAW-winBtn:hover {
22 | filter: brightness( 1.1 );
23 | }
24 | .gsuiDAW-winBtn:empty::before {
25 | content: "Untitled";
26 | font-style: italic;
27 | }
28 | .gsuiDAW-winBtn .gsuiIcon,
29 | .gsuiDAW-winBtn span {
30 | pointer-events: none;
31 | }
32 | .gsuiDAW-winBtn .gsuiIcon + span {
33 | margin-left: 4px;
34 | }
35 |
36 | /* .......................................................................... */
37 | .gsuiDAW-winBtn + .gsuiIcon {
38 | font-size: 12px;
39 | }
40 |
41 | /* .......................................................................... */
42 | .gsuiDAW-winBtn[ data-target="channel" ],
43 | .gsuiDAW-winBtn[ data-target="synthChannel" ] { color: var( --gsuiDAW-winBtn-chan-color ); }
44 | .gsuiDAW-winBtn[ data-target="drums" ],
45 | .gsuiDAW-winBtn[ data-target="pianoroll" ] { color: var( --gsuiDAW-winBtn-pattern-color ); }
46 | .gsuiDAW-winBtn[ data-target="synth" ] { color: var( --gsuiDAW-winBtn-synth-color ); }
47 | .gsuiDAW-winBtn[ data-target="slices" ] { color: var( --gsuiDAW-winBtn-slices-color ); }
48 |
49 | /* .......................................................................... */
50 | .gsuiDAW-window-ctrl {
51 | display: flex;
52 | align-items: center;
53 | gap: inherit;
54 | }
55 | .gsuiDAW-window-playPause {
56 | overflow: hidden;
57 | display: flex;
58 | border-radius: 4px;
59 | }
60 | .gsuiDAW-window-ctrl button {
61 | width: 18px;
62 | height: 16px;
63 | padding: 0;
64 | border: 0;
65 | outline: 0;
66 | color: #fff;
67 | font-size: 8px;
68 | cursor: pointer;
69 | background-color: var( --gsui-btn-playPause-bg );
70 | }
71 | .gsuiDAW-window-playPause button:hover {
72 | color: #fffa;
73 | }
74 | .gsuiDAW-window-ctrl button:hover {
75 | filter: brightness( 1.2 );
76 | }
77 | .gsuiDAW-window-ctrl button:active {
78 | padding-top: 2px;
79 | }
80 | .gsuiDAW-window-ctrl button[ data-icon="play" ] {
81 | padding-left: 2px;
82 | }
83 | .gsuiDAW-window-ctrl button[ data-action="autoscroll" ] {
84 | width: 16px;
85 | border: 2px solid #67a;
86 | border-radius: 999px;
87 | background: none;
88 | }
89 | gsui-window:has( gsui-timewindow[ autoscroll ] ) .gsuiDAW-window-ctrl button[ data-action="autoscroll" ] {
90 | background-color: #67a;
91 | }
92 |
--------------------------------------------------------------------------------
/gsuiDAW/gsuiDAW-windows.html.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | GSUsetTemplate( "gsui-daw-windowHeads", () => [
4 | GSUcreateDiv( { "data-window": "composition" },
5 | GSUgetTemplate( "gsui-daw-window-playPause" ),
6 | ),
7 | GSUcreateDiv( { "data-window": "keys" },
8 | GSUcreateButton( { class: "gsuiDAW-winBtn", "data-target": "pianoroll" } ),
9 | GSUgetTemplate( "gsui-daw-window-playPause" ),
10 | ),
11 | GSUcreateDiv( { "data-window": "synth" },
12 | GSUcreateButton( { class: "gsuiDAW-winBtn", "data-target": "synth" } ),
13 | GSUcreateIcon( { icon: "arrow-right" } ),
14 | GSUcreateButton( { class: "gsuiDAW-winBtn", "data-target": "synthChannel" },
15 | GSUcreateIcon( { icon: "mixer" } ),
16 | GSUcreateSpan(),
17 | ),
18 | ),
19 | GSUcreateDiv( { "data-window": "mixer" } ),
20 | GSUcreateDiv( { "data-window": "effects" },
21 | GSUcreateButton( { class: "gsuiDAW-winBtn", "data-target": "channel" } ),
22 | ),
23 | GSUcreateDiv( { "data-window": "drums" },
24 | GSUcreateButton( { class: "gsuiDAW-winBtn", "data-target": "drums" } ),
25 | GSUgetTemplate( "gsui-daw-window-playPause" ),
26 | ),
27 | GSUcreateDiv( { "data-window": "slices" },
28 | GSUcreateButton( { class: "gsuiDAW-winBtn", "data-target": "slices" } ),
29 | GSUgetTemplate( "gsui-daw-window-playPause" ),
30 | ),
31 | ] );
32 |
33 | GSUsetTemplate( "gsui-daw-window-playPause", () => [
34 | GSUcreateDiv( { "class": "gsuiDAW-window-ctrl" },
35 | GSUcreateDiv( { "class": "gsuiDAW-window-playPause" },
36 | GSUcreateButton( { "data-action": "play", icon: "play" } ),
37 | GSUcreateButton( { "data-action": "stop", icon: "stop" } ),
38 | ),
39 | GSUcreateButton( { "data-action": "autoscroll", icon: "chevron-double-right", title: "Auto scrolling" } ),
40 | ),
41 | ] );
42 |
--------------------------------------------------------------------------------
/gsuiDAW/gsuiDAW.css:
--------------------------------------------------------------------------------
1 | gsui-daw {
2 | --radius: 4px;
3 | --gap: 4px;
4 | display: flex;
5 | flex-direction: column;
6 | position: relative;
7 | box-sizing: border-box;
8 | width: 100%;
9 | height: 100%;
10 | font-size: 16px;
11 | background-color: var( --gsui-app-bg );
12 | --gsuiDAW-winBtn-bg: #0004;
13 | --gsuiDAW-winBtn-chan-color: #ce93d8;
14 | --gsuiDAW-winBtn-synth-color: #a5d6a7;
15 | --gsuiDAW-winBtn-slices-color: #e29d8a;
16 | --gsuiDAW-winBtn-pattern-color: #81d4fa;
17 | }
18 |
19 | /* .......................................................................... */
20 | .gsuiDAW-head {
21 | display: grid;
22 | padding: var( --gap );
23 | gap: var( --gap );
24 | grid-template:
25 | "areaUser areaCtrl areaVisu areaHelp" 28px
26 | "areaUser areaTime areaWins areaVers" 20px
27 | /min-content min-content min-content 1fr;
28 | border-bottom: 2px solid var( --gsui-win-brd );
29 | background-color: var( --gsui-head1-bg );
30 | }
31 | .gsuiDAW-area {
32 | display: flex;
33 | gap: inherit;
34 | }
35 | .gsuiDAW-areaUser {
36 | grid-area: areaUser;
37 | }
38 | .gsuiDAW-body[ resources-hidden ] .gsuiDAW-resources {
39 | display: none;
40 | }
41 | .gsuiDAW-body[ resources-hidden ] .gsuiDAW-windows {
42 | left: 0 !important;
43 | width: 100% !important;
44 | }
45 | .gsuiDAW-resources {
46 | display: flex;
47 | width: 300px;
48 | min-width: 330px;
49 | max-width: 700px;
50 | border-right: 3px solid var( --gsui-win-brd );
51 | background-color: var( --gsui-items-bg );
52 | }
53 | .gsuiDAW-libraries {
54 | flex: 1;
55 | border: inherit;
56 | border-right-width: 2px;
57 | }
58 | .gsuiDAW-patterns {
59 | flex: 1;
60 | }
61 | .gsuiDAW-windows {
62 | flex: 1;
63 | }
64 | gsui-daw gsui-windows {
65 | z-index: 0;
66 | background-image: url( "data:image/svg+xml,%3Csvg width='6' height='6' viewBox='0 0 6 6' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='%23000000' fill-opacity='0.2' fill-rule='evenodd'%3E%3Cpath d='M5 0h1L0 6V5zM6 5v1H5z'/%3E%3C/g%3E%3C/svg%3E" );
67 | background-attachment: local;
68 | }
69 |
--------------------------------------------------------------------------------
/gsuiDotline/gsuiDotline.css:
--------------------------------------------------------------------------------
1 | gsui-dotline {
2 | --gsuiDotline-dotSize: 4px;
3 | --gsuiDotline-cdotSize: 8px;
4 | display: block;
5 | width: 100%;
6 | height: 100%;
7 | position: relative;
8 | stroke: currentColor;
9 | stroke-width: 2px;
10 | touch-action: none;
11 | }
12 |
13 | /* .......................................................................... */
14 | .gsuiDotline-padding {
15 | position: absolute;
16 | z-index: 0;
17 | inset: calc( var( --gsuiDotline-dotSize ) / 2 );
18 | }
19 |
20 | /* .......................................................................... */
21 | gsui-dotline svg {
22 | position: absolute;
23 | left: 0;
24 | top: 0;
25 | width: 100%;
26 | height: 100%;
27 | }
28 | gsui-dotline path {
29 | fill: none;
30 | }
31 | gsui-dotline gsui-beatlines + gsui-beatlines {
32 | --gsui-deg: 0deg;
33 | }
34 |
35 | /* .......................................................................... */
36 | gsui-dotline gsui-slider {
37 | width: 10px;
38 | height: 32px;
39 | opacity: 0;
40 | pointer-events: none;
41 | }
42 |
43 | /* .......................................................................... */
44 | .gsuiDotline-dot,
45 | .gsuiDotline-cdot {
46 | position: absolute;
47 | box-sizing: border-box;
48 | border-radius: 50%;
49 | width: var( --w );
50 | height: var( --w );
51 | margin:
52 | calc( var( --w ) / -2 ) 0 0
53 | calc( var( --w ) / -2 );
54 | }
55 | .gsuiDotline-dot {
56 | --w: var( --gsuiDotline-dotSize );
57 | z-index: 2;
58 | background-color: currentColor;
59 | }
60 | .gsuiDotline-cdot {
61 | --w: var( --gsuiDotline-cdotSize );
62 | z-index: 1;
63 | border: 1px solid;
64 | transition:
65 | .2s width,
66 | .2s height,
67 | .2s margin;
68 | }
69 | .gsuiDotline-dot::before,
70 | .gsuiDotline-cdot::before {
71 | content: "";
72 | position: absolute;
73 | inset: -4px;
74 | border-radius: 50%;
75 | }
76 | .gsuiDotline-dot:hover::before,
77 | .gsuiDotline-cdot:hover::before,
78 | .gsuiDotline-dotSelected::before {
79 | background-color: #fff3;
80 | }
81 | .gsuiDotline-cdot[ data-type="hold" ],
82 | .gsuiDotline-cdot[ data-type="line" ] {
83 | display: none;
84 | }
85 |
--------------------------------------------------------------------------------
/gsuiDotline/gsuiDotline.html.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | GSUsetTemplate( "gsui-dotline", () => (
4 | GSUcreateDiv( { class: "gsuiDotline-padding" },
5 | GSUcreateElement( "gsui-slider", { type: "linear-y", min: -32, max: 32, step: .01, "mousemove-size": 2000 } ),
6 | GSUcreateElement( "gsui-dotlinesvg" ),
7 | )
8 | ) );
9 |
--------------------------------------------------------------------------------
/gsuiDotlineSVG/gsuiDotlineSVG.html.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | GSUsetTemplate( "gsui-dotlinesvg", () =>
4 | GSUcreateElementSVG( "svg", { preserveAspectRatio: "none", inert: true },
5 | GSUcreateElementSVG( "path" ),
6 | )
7 | );
8 |
--------------------------------------------------------------------------------
/gsuiDotlineSVG/gsuiDotlineSVG.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | class gsuiDotlineSVG extends gsui0ne {
4 | #w = 1;
5 | #h = 1;
6 | #xmin = 0;
7 | #ymin = 0;
8 | #xmax = 0;
9 | #ymax = 0;
10 | #svgW = 0;
11 | #svgH = 0;
12 | #resW = 500;
13 |
14 | constructor() {
15 | super( {
16 | $cmpName: "gsuiDotlineSVG",
17 | $tagName: "gsui-dotlinesvg",
18 | $elements: {
19 | $svg: "svg",
20 | $path: "path",
21 | },
22 | } );
23 | Object.seal( this );
24 | }
25 |
26 | // .........................................................................
27 | $setSVGSize( w, h ) {
28 | this.#svgW = w;
29 | this.#svgH = h;
30 | this.#resW = w * 2;
31 | GSUsetViewBoxWH( this.$elements.$svg, w, h );
32 | }
33 | $setDataBox( box ) {
34 | const n = box.split( " " );
35 |
36 | this.#xmin = +n[ 0 ];
37 | this.#ymin = +n[ 1 ];
38 | this.#xmax = +n[ 2 ];
39 | this.#ymax = +n[ 3 ];
40 | this.#w = this.#xmax - this.#xmin;
41 | this.#h = this.#ymax - this.#ymin;
42 | }
43 | $setCurve( data ) {
44 | const xy = GSUmathSampleDotLine( data, this.#resW );
45 | const curveDots = [];
46 |
47 | if ( xy.length > 1 ) {
48 | const xy0 = xy.shift();
49 |
50 | curveDots.push( "M", this.#calcX( xy0[ 0 ] ), this.#calcY( xy0[ 1 ] ) );
51 | xy.forEach( dot => curveDots.push( "L", this.#calcX( dot[ 0 ] ), this.#calcY( dot[ 1 ] ) ) );
52 | }
53 | GSUsetAttribute( this.$elements.$path, "d", curveDots.join( " " ) );
54 | }
55 |
56 | // .........................................................................
57 | #calcX( x ) {
58 | return GSUmathFix( ( x - this.#xmin ) / this.#w * this.#svgW, 5 );
59 | }
60 | #calcY( y ) {
61 | return GSUmathFix( this.#svgH - ( y - this.#ymin ) / this.#h * this.#svgH, 5 );
62 | }
63 | }
64 |
65 | GSUdefineElement( "gsui-dotlinesvg", gsuiDotlineSVG );
66 |
--------------------------------------------------------------------------------
/gsuiDragline/gsuiDragline.css:
--------------------------------------------------------------------------------
1 | :root {
2 | --gsuiDragline-color: #fff;
3 | --gsuiDragline-dotSize: 8px;
4 | --gsuiDragline-dotRad: 50%;
5 | --gsuiDragline-lineSize: 4px;
6 | }
7 |
8 | /* ................................................................ */
9 | .gsuiDragline {
10 | position: absolute;
11 | max-width: 0;
12 | max-height: 0;
13 | color: var( --gsuiDragline-color );
14 | }
15 | .gsuiDragline-dragging,
16 | .gsuiDragline-dragging .gsuiDragline-to {
17 | pointer-events: none;
18 | }
19 |
20 | /* ................................................................ */
21 | .gsuiDragline-main {
22 | position: relative;
23 | pointer-events: none;
24 | }
25 |
26 | /* ................................................................ */
27 | .gsuiDragline-line {
28 | position: absolute;
29 | bottom: 0;
30 | right: 0;
31 | width: 0;
32 | height: 0;
33 | fill: none;
34 | stroke: currentColor;
35 | stroke-width: var( --gsuiDragline-lineSize );
36 | stroke-linecap: round;
37 | }
38 | .gsuiDragline-down .gsuiDragline-line {
39 | top: 0;
40 | bottom: auto;
41 | }
42 | .gsuiDragline-right .gsuiDragline-line {
43 | left: 0;
44 | right: auto;
45 | }
46 |
47 | /* ................................................................ */
48 | .gsuiDragline-to {
49 | position: absolute;
50 | width: var( --gsuiDragline-dotSize );
51 | height: var( --gsuiDragline-dotSize );
52 | margin: calc( var( --gsuiDragline-dotSize ) / -2 );
53 | cursor: pointer;
54 | border-radius: var( --gsuiDragline-dotRad );
55 | pointer-events: all;
56 | background-color: var( --gsuiDragline-color );
57 | transition: .2s background-color;
58 | }
59 | .gsuiDragline-down .gsuiDragline-to { bottom: 0; }
60 | .gsuiDragline-right .gsuiDragline-to { right: 0; }
61 | .gsuiDragline-main:not( .gsuiDragline-down ) .gsuiDragline-to { top: 0; }
62 | .gsuiDragline-main:not( .gsuiDragline-right ) .gsuiDragline-to { left: 0; }
63 |
64 | /* ................................................................ */
65 | .gsuiDragline-drop {
66 | position: relative;
67 | max-width: 0;
68 | max-height: 0;
69 | }
70 | .gsuiDragline-drop::before {
71 | content: "";
72 | position: absolute;
73 | width: 0;
74 | height: 0;
75 | margin: 0;
76 | background-color: var( --gsuiDragline-color );
77 | transition: .2s all;
78 | }
79 | .gsuiDragline-dropActive::before {
80 | width: var( --gsuiDragline-dotSize );
81 | height: var( --gsuiDragline-dotSize );
82 | margin: calc( var( --gsuiDragline-dotSize ) / -2 );
83 | cursor: pointer;
84 | border-radius: var( --gsuiDragline-dotRad );
85 | }
86 | .gsuiDragline-dropActive:hover::before {
87 | transform: scale( 2 );
88 | }
89 |
--------------------------------------------------------------------------------
/gsuiDragline/gsuiDragline.html.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | GSUsetTemplate( "gsui-dragline", () =>
4 | GSUcreateDiv( { class: "gsuiDragline" },
5 | GSUcreateDiv( { class: "gsuiDragline-main" },
6 | GSUcreateElementSVG( "svg", { class: "gsuiDragline-line" },
7 | GSUcreateElementSVG( "polyline" ),
8 | ),
9 | GSUcreateDiv( { class: "gsuiDragline-to" } ),
10 | ),
11 | )
12 | );
13 |
--------------------------------------------------------------------------------
/gsuiDropdown/gsuiDropdown.css:
--------------------------------------------------------------------------------
1 | .gsuiDropdown {
2 | --bg-color: #555;
3 | --brd-color: #333;
4 | --brd: 2px solid var( --brd-color );
5 | z-index: 2;
6 | position: absolute;
7 | box-sizing: border-box;
8 | display: flex;
9 | border-radius: 6px;
10 | opacity: 0;
11 | visibility: hidden;
12 | box-shadow: 0 4px 10px 5px #0003;
13 | transition: .2s;
14 | transition-property: opacity, visibility;
15 | }
16 | .gsuiDropdown[ data-open ] {
17 | opacity: 1;
18 | visibility: visible;
19 | }
20 |
21 | /* .......................................................................... */
22 | .gsuiDropdown-content {
23 | position: relative;
24 | width: 100%;
25 | padding: 4px;
26 | border: var( --brd );
27 | border-radius: inherit;
28 | background-color: var( --bg-color );
29 | }
30 |
31 | /* .......................................................................... */
32 | .gsuiDropdown-arrow {
33 | content: "";
34 | position: absolute;
35 | box-sizing: border-box;
36 | top: -3px;
37 | left: 50%;
38 | width: 8px;
39 | height: 8px;
40 | margin-top: -4px;
41 | margin-left: -4px;
42 | border: var( --brd );
43 | border-right: 0;
44 | border-bottom: 0;
45 | border-radius: 2px 0 0 0;
46 | background-color: var( --bg-color );
47 | background-color: var( --brd-color );
48 | transform: rotate( 45deg );
49 | }
50 | .gsuiDropdown[ data-dir^="top" ] .gsuiDropdown-arrow {
51 | transform: rotate( 225deg );
52 | }
53 |
--------------------------------------------------------------------------------
/gsuiDrum/gsuiDrum.css:
--------------------------------------------------------------------------------
1 | gsui-drum,
2 | gsui-drumcut {
3 | position: absolute;
4 | width: 1em;
5 | }
6 | gsui-drum {
7 | height: 66%;
8 | }
9 | gsui-drumcut {
10 | container: gsuiDrumcut-query / inline-size;
11 | bottom: 1px;
12 | height: calc( 34% - 2px );
13 | }
14 |
15 | /* .......................................................................... */
16 | .gsuiDrum-in,
17 | .gsuiDrumcut-in {
18 | display: flex;
19 | box-sizing: border-box;
20 | align-items: center;
21 | flex-direction: column;
22 | justify-content: center;
23 | height: 100%;
24 | border-radius: 3px;
25 | border-top: 2px solid #ffffff4f;
26 | border-bottom: 2px solid #0000001f;
27 | border-right: 1px solid #00000033;
28 | background-color: var( --gsuiDrums-drum-bg );
29 | }
30 | .gsuiDrumcut-in {
31 | font-size: 10px;
32 | background-color: var( --gsuiDrums-drumcut-bg );
33 | }
34 | .gsuiDrumcut-in .gsuiIcon {
35 | opacity: .6;
36 | }
37 |
38 | /* .......................................................................... */
39 | .gsuiDrum-prop {
40 | position: relative;
41 | width: 100%;
42 | height: 3px;
43 | background-color: var( --gsuiDrums-drumprop-bg );
44 | transition: .1s height;
45 | }
46 | .gsuiDrums-lineOpen[ data-prop="pan" ] .gsuiDrum-prop[ data-value="pan" ],
47 | .gsuiDrums-lineOpen[ data-prop="gain" ] .gsuiDrum-prop[ data-value="gain" ],
48 | .gsuiDrums-lineOpen[ data-prop="detune" ] .gsuiDrum-prop[ data-value="detune" ] {
49 | height: 6px;
50 | }
51 | .gsuiDrum-prop + .gsuiDrum-prop {
52 | margin-top: 2px;
53 | }
54 | .gsuiDrum-propValue {
55 | position: absolute;
56 | height: 100%;
57 | background-color: var( --gsuiDrums-drumprop-color );
58 | }
59 |
60 | /* .......................................................................... */
61 | @container gsuiDrumcut-query ( max-width: 14px ) {
62 | .gsuiDrumcut-in .gsuiIcon {
63 | display: none;
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/gsuiDrum/gsuiDrum.html.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | GSUsetTemplate( "gsui-drum", () =>
4 | GSUcreateDiv( { class: "gsuiDrum-in", inert: true },
5 | [ "detune", "pan", "gain" ].map( p =>
6 | GSUcreateDiv( { class: "gsuiDrum-prop", "data-value": p },
7 | GSUcreateDiv( { class: "gsuiDrum-propValue" } ),
8 | )
9 | ),
10 | )
11 | );
12 |
13 | GSUsetTemplate( "gsui-drumcut", () =>
14 | GSUcreateDiv( { class: "gsuiDrumcut-in", inert: true },
15 | GSUcreateIcon( { icon: "drumcut" } ),
16 | )
17 | );
18 |
--------------------------------------------------------------------------------
/gsuiDrum/gsuiDrum.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | class gsuiDrum extends gsui0ne {
4 | constructor() {
5 | super( {
6 | $cmpName: "gsuiDrum",
7 | $tagName: "gsui-drum",
8 | } );
9 | Object.seal( this );
10 | }
11 |
12 | static get observedAttributes() {
13 | return [ "when", "duration", "gain", "pan", "detune" ];
14 | }
15 | $attributeChanged( prop, val ) {
16 | switch ( prop ) {
17 | case "when":
18 | this.style.left = `${ val }em`;
19 | break;
20 | case "duration":
21 | this.style.width = `${ val }em`;
22 | break;
23 | case "pan":
24 | case "gain":
25 | case "detune":
26 | this.#changeProp( prop, +val );
27 | break;
28 | }
29 | }
30 |
31 | // .........................................................................
32 | #changeProp( prop, val ) {
33 | const st = {};
34 |
35 | switch ( prop ) {
36 | case "detune":
37 | st.left = val > 0 ? "50%" : `${ ( 1 + val / 12 ) * 50 }%`;
38 | st.width = `${ Math.abs( val / 12 ) * 50 }%`;
39 | break;
40 | case "pan":
41 | st.left = val > 0 ? "50%" : `${ ( 1 + val ) * 50 }%`;
42 | st.width = `${ Math.abs( val ) * 50 }%`;
43 | break;
44 | case "gain":
45 | st.left = 0;
46 | st.width = `${ val * 100 }%`;
47 | break;
48 | }
49 | GSUsetStyle( this.querySelector( `.gsuiDrum-prop[data-value="${ prop }"]` ).firstChild, st );
50 | }
51 | }
52 |
53 | GSUdefineElement( "gsui-drum", gsuiDrum );
54 |
--------------------------------------------------------------------------------
/gsuiDrum/gsuiDrumcut.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | class gsuiDrumcut extends gsui0ne {
4 | constructor() {
5 | super( {
6 | $cmpName: "gsuiDrumcut",
7 | $tagName: "gsui-drumcut",
8 | } );
9 | Object.seal( this );
10 | }
11 |
12 | static get observedAttributes() {
13 | return [ "when", "duration" ];
14 | }
15 | $attributeChanged( prop, val ) {
16 | switch ( prop ) {
17 | case "when":
18 | this.style.left = `${ val }em`;
19 | break;
20 | case "duration":
21 | this.style.width = `${ val }em`;
22 | break;
23 | }
24 | }
25 | }
26 |
27 | GSUdefineElement( "gsui-drumcut", gsuiDrumcut );
28 |
--------------------------------------------------------------------------------
/gsuiDrumrow/gsuiDrumrow.html.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | GSUsetTemplate( "gsui-drumrow", () => [
4 | GSUcreateDiv( { class: "gsuiDrumrow-grip" },
5 | GSUcreateIcon( { icon: "grip-v" } ),
6 | ),
7 | GSUcreateDiv( { class: "gsuiDrumrow-main" },
8 | GSUcreateElement( "gsui-toggle", { title: "Toggle the drumrow (right click for solo)" } ),
9 | GSUcreateButton( { class: "gsuiDrumrow-btnProps", "data-action": "props", icon: "drumprops", title: "Expand props panel" } ),
10 | GSUcreateButton( { class: "gsuiDrumrow-btnDelete", "data-action": "delete", icon: "close", title: "Remove the drumrow" } ),
11 | GSUcreateSpan( { class: "gsuiDrumrow-name" } ),
12 | GSUcreateDiv( { class: "gsuiDrumrow-waveWrap" } ),
13 | GSUcreateDiv( { class: "gsuiDrumrow-detune", title: "pitch" },
14 | GSUcreateElement( "gsui-slider", { type: "linear-y", min: -12, max: 12, step: 1, "mousemove-size": 400, "data-prop": "detune", defaultValue: 0 } ),
15 | ),
16 | GSUcreateDiv( { class: "gsuiDrumrow-pan", title: "pan" },
17 | GSUcreateElement( "gsui-slider", { type: "linear-y", min: -1, max: 1, step: .02, "mousemove-size": 400, "data-prop": "pan", defaultValue: 0 } ),
18 | ),
19 | GSUcreateDiv( { class: "gsuiDrumrow-gain", title: "gain" },
20 | GSUcreateElement( "gsui-slider", { type: "linear-y", min: 0, max: 1, step: .01, "mousemove-size": 400, "data-prop": "gain", defaultValue: 1 } ),
21 | ),
22 | ),
23 | GSUcreateElement( "gsui-prop-select", { props: "gain pan detune:pitch" } ),
24 | ] );
25 |
--------------------------------------------------------------------------------
/gsuiDrumrows/gsuiDrumrows.css:
--------------------------------------------------------------------------------
1 | gsui-drumrows {
2 | display: flex;
3 | flex-direction: column;
4 | font-size: var( --gsuiTimewindow-lineH );
5 | }
6 | gsui-drumrows::-webkit-scrollbar {
7 | display: none;
8 | }
9 |
10 | .gsuiDrumrows-dropNew {
11 | display: flex;
12 | align-items: center;
13 | justify-content: center;
14 | order: 2147483647;
15 | height: 1em;
16 | }
17 |
--------------------------------------------------------------------------------
/gsuiDrums/gsuiDrums.css:
--------------------------------------------------------------------------------
1 | gsui-drums {
2 | display: block;
3 | height: 100%;
4 | }
5 |
6 | /* .......................................................................... */
7 | gsui-drums .gsuiTimewindow-currentTime {
8 | margin-left: 0;
9 | width: var( --gsuiDrums-pxperstep, 1px );
10 | opacity: .1;
11 | }
12 | gsui-drums gsui-timewindow[ currenttime="0" ] .gsuiTimewindow-currentTime {
13 | display: block;
14 | }
15 | gsui-drums gsui-step-select,
16 | gsui-drums gsui-slider[ data-zoom="y" ] {
17 | display: none;
18 | }
19 | gsui-drums .gsuiTimewindow-rows {
20 | display: flex;
21 | flex-direction: column;
22 | }
23 |
24 | /* .......................................................................... */
25 | .gsuiDrums-line {
26 | position: relative;
27 | width: 1000000px;
28 | font-size: var( --gsuiTimewindow-lineH );
29 | height: 1em;
30 | box-sizing: border-box;
31 | border-bottom: 1px solid var( --gsuiDrums-line-border );
32 | transition: .2s height, .1s filter, .1s background-color;
33 | }
34 | .gsuiDrums-lineOpen {
35 | height: calc( 1em + 1.5em );
36 | }
37 | .gsuiDrums-line.gsuiDrumrow-mute {
38 | filter: brightness( .8 ) contrast( .8 );
39 | background-color: var( --gsuiDrums-line-mute-bg );
40 | }
41 | .gsuiDrums-lineDrums {
42 | position: absolute;
43 | inset: 0;
44 | height: 1em;
45 | }
46 | .gsuiDrums-lineIn {
47 | height: 100%;
48 | box-sizing: border-box;
49 | border-bottom: 1px dashed var( --gsuiDrums-line-border );
50 | font-size: var( --gsuiTimewindow-pxperbeat );
51 | cursor: pointer;
52 | }
53 | .gsuiDrums-lineProps {
54 | position: absolute;
55 | inset: 1em 0 0;
56 | }
57 |
58 | /* .......................................................................... */
59 | .gsuiDrums-drumHover,
60 | .gsuiDrums-drumcutHover {
61 | position: absolute;
62 | z-index: 1;
63 | background-color: #0002;
64 | }
65 | .gsuiDrums-drumHover {
66 | height: 66%;
67 | }
68 | .gsuiDrums-drumcutHover {
69 | bottom: 0;
70 | height: 34%;
71 | }
72 | .gsuiDrums-drumcutHoverIn,
73 | .gsuiDrums-drumHoverIn {
74 | box-sizing: border-box;
75 | height: 100%;
76 | margin: 0 1px 1px 0;
77 | border: 2px solid var( --gsuiDrums-drumHover-border );
78 | border-radius: 4px;
79 | background-color: var( --gsuiDrums-drumHover-bg );
80 | pointer-events: none;
81 | }
82 |
83 | /* .......................................................................... */
84 | .gsuiDrums-previewDeleted,
85 | .gsuiDrums-preview {
86 | opacity: .4;
87 | }
88 |
--------------------------------------------------------------------------------
/gsuiDrums/gsuiDrums.html.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | GSUsetTemplate( "gsui-drums-line", () =>
4 | GSUcreateDiv( { class: "gsuiDrums-line" },
5 | GSUcreateDiv( { class: "gsuiDrums-lineDrums" },
6 | GSUcreateDiv( { class: "gsuiDrums-lineIn" } ),
7 | ),
8 | GSUcreateDiv( { class: "gsuiDrums-lineProps" },
9 | GSUcreateElement( "gsui-slidergroup" ),
10 | ),
11 | )
12 | );
13 |
--------------------------------------------------------------------------------
/gsuiEffect/gsuiEffect.html.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | GSUsetTemplate( "gsui-effect", () => [
4 | GSUcreateDiv( { class: "gsuiEffect-head" },
5 | GSUcreateDiv( { class: "gsuiEffect-grip gsuiIcon", "data-icon": "grip-v" } ),
6 | GSUcreateButton( { class: "gsuiEffect-expand", icon: "caret-right" } ),
7 | GSUcreateElement( "gsui-toggle", { off: true, title: "Toggle this effect" } ),
8 | GSUcreateSpan( { class: "gsuiEffect-name" } ),
9 | GSUcreateElement( "gsui-help-link" ),
10 | GSUcreateButton( { class: "gsuiEffect-remove", icon: "close", title: "Delete this effect" } ),
11 | ),
12 | GSUcreateDiv( { class: "gsuiEffect-content" } ),
13 | ] );
14 |
--------------------------------------------------------------------------------
/gsuiEffect/gsuiEffect.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | class gsuiEffect extends gsui0ne {
4 | constructor() {
5 | super( {
6 | $cmpName: "gsuiEffect",
7 | $tagName: "gsui-effect",
8 | $elements: {
9 | $toggle: "gsui-toggle",
10 | $name: ".gsuiEffect-name",
11 | $help: "gsui-help-link",
12 | $expand: ".gsuiEffect-expand",
13 | $remove: ".gsuiEffect-remove",
14 | $content: ".gsuiEffect-content",
15 | },
16 | } );
17 | Object.seal( this );
18 |
19 | this.$elements.$expand.onclick = () => {
20 | GSUtoggleAttribute( this, "expanded" );
21 | this.$dispatch( "expand" );
22 | };
23 | this.$elements.$remove.onclick = () => this.$dispatch( "remove" );
24 | GSUlistenEvents( this, {
25 | gsuiToggle: {
26 | toggle: ( d, t ) => {
27 | GSUtoggleAttribute( this, "enable" );
28 | this.$dispatch( "toggle" );
29 | },
30 | },
31 | } );
32 | }
33 |
34 | // .........................................................................
35 | static get observedAttributes() {
36 | return [ "order", "enable", "name" ];
37 | }
38 | $attributeChanged( prop, val ) {
39 | switch ( prop ) {
40 | case "order":
41 | this.style.order = val;
42 | break;
43 | case "enable":
44 | GSUsetAttribute( this.$elements.$toggle, "off", val !== "" );
45 | GSUsetAttribute( this.$elements.$content.firstChild, "off", val !== "" );
46 | break;
47 | case "name":
48 | this.$elements.$name.textContent = val;
49 | GSUsetAttribute( this.$elements.$help, "page", `mixer-effects-${ val }` );
50 | break;
51 | }
52 | }
53 |
54 | // .........................................................................
55 | $setFxElement( elFx ) {
56 | this.$elements.$content.append( elFx );
57 | }
58 | $getFxElement() {
59 | return this.$elements.$content?.firstChild;
60 | }
61 | }
62 |
63 | GSUdefineElement( "gsui-effect", gsuiEffect );
64 |
--------------------------------------------------------------------------------
/gsuiEffects/gsuiEffects.css:
--------------------------------------------------------------------------------
1 | gsui-effects {
2 | display: flex;
3 | height: 100%;
4 | overflow: auto;
5 | flex-direction: column;
6 | background-color: var( --gsui-items-bg );
7 | }
8 |
9 | /* .......................................................................... */
10 | .gsuiEffects-list {
11 | display: flex;
12 | overflow: auto;
13 | flex-direction: column;
14 | }
15 |
16 | /* .......................................................................... */
17 | .gsuiEffects-addBtn {
18 | position: relative;
19 | order: 2147483646;
20 | border: 0;
21 | outline: 0;
22 | width: 100%;
23 | min-height: 52px;
24 | color: inherit;
25 | font-size: 18px;
26 | cursor: pointer;
27 | background: none;
28 | opacity: .4;
29 | transition: .2s opacity;
30 | }
31 | .gsuiEffects-addBtn:hover {
32 | opacity: .7;
33 | }
34 | .gsuiEffects-addBtn::before {
35 | content: "";
36 | position: absolute;
37 | inset: 6px;
38 | border: 2px dashed;
39 | border-radius: 4px;
40 | opacity: .4;
41 | }
42 | .gsuiEffects-addBtn:active,
43 | .gsuiEffects-addBtn:active .gsuiEffects-addBtn::before {
44 | margin-top: 2px;
45 | }
46 |
--------------------------------------------------------------------------------
/gsuiEffects/gsuiEffects.html.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | GSUsetTemplate( "gsui-effects", () => [
4 | GSUcreateButton( { class: "gsuiEffects-addBtn", title: "Add an effect" },
5 | GSUcreateIcon( { icon: "add-effect" } ),
6 | ),
7 | ] );
8 |
--------------------------------------------------------------------------------
/gsuiEnvelope/gsuiEnvelope.html.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | GSUsetTemplate( "gsui-envelope", () =>
4 | GSUcreateDiv( { class: "gsuiEnvelope-in" },
5 | GSUcreateDiv( { class: "gsuiEnvelope-props" },
6 | [
7 | [ "attack", "attack", "att", 0, 1, .01 ],
8 | [ "hold", "hold", "hold", 0, 1, .01 ],
9 | [ "decay", "decay", "dec", 0, 1, .01 ],
10 | [ "sustain", "sustain", "sus", 0, 1, .01 ],
11 | [ "release", "release", "rel", 0, 4, .01 ],
12 | [ "amp", "amplification", "pitch", -24, 24, 1 ],
13 | [ "q", "Q", "Q", 0, 25, .01 ],
14 | ].map( ( [ prop, title, text, min, max, step ] ) =>
15 | GSUcreateDiv( { class: "gsuiEnvelope-prop", title, "data-prop": prop },
16 | GSUcreateDiv( { class: "gsuiEnvelope-propLabel" }, text ),
17 | GSUcreateDiv( { class: "gsuiEnvelope-propValue" } ),
18 | GSUcreateElement( "gsui-slider", { type: "linear-x", disabled: true, min, max, step, "mousemove-size": "800", "data-prop": prop } ),
19 | )
20 | ),
21 | ),
22 | GSUcreateDiv( { class: "gsuiEnvelope-graph", inert: true },
23 | GSUcreateElement( "gsui-beatlines", { coloredbeats: "" } ),
24 | GSUcreateElement( "gsui-envelope-graph" ),
25 | GSUcreateDiv( { class: "gsuiEnvelope-keyPreviews" } ),
26 | ),
27 | )
28 | );
29 |
--------------------------------------------------------------------------------
/gsuiEnvelopeGraph/gsuiEnvelopeGraph.css:
--------------------------------------------------------------------------------
1 | gsui-envelope-graph {
2 | transition: color .2s;
3 | }
4 | gsui-envelope-graph svg {
5 | width: 100%;
6 | height: 100%;
7 | stroke: currentColor;
8 | stroke-width: 2px;
9 | }
10 | .gsuiEnvelopeGraph-line {
11 | fill: transparent;
12 | }
13 | .gsuiEnvelopeGraph-mainLine {
14 | stroke-dasharray: 12 4;
15 | stroke-opacity: .5;
16 | fill: currentColor;
17 | fill-opacity: .05;
18 | }
19 |
--------------------------------------------------------------------------------
/gsuiEnvelopeGraph/gsuiEnvelopeGraph.html.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | GSUsetTemplate( "gsui-envelope-graph", () =>
4 | GSUcreateElementSVG( "svg", { preserveAspectRatio: "none" },
5 | GSUcreateElementSVG( "polyline", { class: "gsuiEnvelopeGraph-mainLine" } ),
6 | GSUcreateElementSVG( "polyline", { class: "gsuiEnvelopeGraph-line" } ),
7 | GSUcreateElementSVG( "polyline", { class: "gsuiEnvelopeGraph-line" } ),
8 | )
9 | );
10 |
--------------------------------------------------------------------------------
/gsuiEnvelopeGraph/gsuiEnvelopeGraph.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | class gsuiEnvelopeGraph extends gsui0ne {
4 | $amp = 1;
5 | $attack = .25;
6 | $hold = .25;
7 | $decay = .25;
8 | $sustain = .8;
9 | $release = 1;
10 | $duration = 4;
11 |
12 | constructor() {
13 | super( {
14 | $cmpName: "gsuiEnvelopeGraph",
15 | $tagName: "gsui-envelope-graph",
16 | $elements: {
17 | $svg: "svg",
18 | $mainLine: ".gsuiEnvelopeGraph-mainLine",
19 | $attLine: ".gsuiEnvelopeGraph-line",
20 | $relLine: ".gsuiEnvelopeGraph-line + .gsuiEnvelopeGraph-line",
21 | },
22 | } );
23 | Object.seal( this );
24 | }
25 |
26 | // .........................................................................
27 | $firstTimeConnected() {
28 | this.$resized();
29 | }
30 |
31 | // .........................................................................
32 | $resized() {
33 | GSUsetViewBoxWH( this.$elements.$svg, this.clientWidth, this.clientHeight );
34 | this.$draw();
35 | }
36 | $draw() {
37 | if ( this.firstChild ) {
38 | const pts = gsuiEnvelopeGraph.#getPoints(
39 | this.clientWidth, this.clientHeight, this.$duration,
40 | Math.abs( this.$amp ), this.$attack, this.$hold, this.$decay, this.$sustain, this.$release );
41 |
42 | GSUsetAttribute( this.$elements.$attLine, "points", pts.slice( 0, 8 ).join( " " ) );
43 | GSUsetAttribute( this.$elements.$relLine, "points", pts.slice( -4 ).join( " " ) );
44 | GSUsetAttribute( this.$elements.$mainLine, "points", pts.join( " " ) );
45 | }
46 | }
47 | static #getPoints( w, h, dur, amp, att, hold, dec, sus, rel ) {
48 | const dur2 = dur !== "auto" ? dur : att + hold + dec + 1 + rel;
49 | const bpp = w / dur2;
50 | const attX = bpp * att;
51 | const holX = attX + bpp * hold;
52 | const decX = holX + bpp * dec;
53 | const susX = decX + bpp * ( dur === "auto" ? 1 : dur - att - hold - dec - rel );
54 | const relX = susX + bpp * rel;
55 | const holY = h - ( h * amp );
56 | const susY = h - ( h * amp * sus );
57 |
58 | return [
59 | 0, h,
60 | attX, holY,
61 | holX, holY,
62 | decX, susY,
63 | susX, susY,
64 | relX, h,
65 | ];
66 | }
67 | }
68 |
69 | GSUdefineElement( "gsui-envelope-graph", gsuiEnvelopeGraph );
70 |
--------------------------------------------------------------------------------
/gsuiFxDelay/gsuiFxDelay.css:
--------------------------------------------------------------------------------
1 | gsui-fx-delay {
2 | display: flex;
3 | flex-direction: column;
4 | box-sizing: border-box;
5 | gap: 8px;
6 | height: 100%;
7 | min-width: 160px;
8 | min-height: 110px;
9 | padding: 8px;
10 | }
11 |
12 | /* .......................................................................... */
13 | .gsuiEffect-param-row gsui-slider {
14 | flex: 1;
15 | height: 10px;
16 | }
17 | .gsuiEffect-param-row[ data-prop="time" ] gsui-slider { --gsuiSlider-lineColor: var( --gsui-col-time ) }
18 | .gsuiEffect-param-row[ data-prop="gain" ] gsui-slider { --gsuiSlider-lineColor: var( --gsui-col-gain ) }
19 | .gsuiEffect-param-row[ data-prop="pan" ] gsui-slider { --gsuiSlider-lineColor: var( --gsui-col-pan ) }
20 | .gsuiEffect-param-row .gsuiSlider-eventCatcher {
21 | inset: -4px 0;
22 | }
23 |
24 | /* .......................................................................... */
25 | gsui-fx-delay .gsuiEffect-param-label {
26 | width: 30px;
27 | }
28 | gsui-fx-delay .gsuiEffect-param-value {
29 | width: 52px;
30 | }
31 | .gsuiEffect-param-row[ data-prop="time" ] .gsuiEffect-param-value::after {
32 | content: " b";
33 | }
34 | .gsuiEffect-param-row[ data-prop="pan" ] .gsuiEffect-param-value::after,
35 | .gsuiEffect-param-row[ data-prop="gain" ] .gsuiEffect-param-value::after {
36 | content: " %";
37 | }
38 |
39 | /* .......................................................................... */
40 | .gsuiFxDelay-graph {
41 | position: relative;
42 | overflow: hidden;
43 | flex: 1;
44 | border-radius: 6px;
45 | background-color: var( --gsui-screen-graph );
46 | }
47 | .gsuiFxDelay-graph-lines {
48 | position: absolute;
49 | inset: 0;
50 | }
51 | .gsuiFxDelay-graph-line {
52 | position: absolute;
53 | top: calc( 50% - 1px );
54 | width: 100%;
55 | height: 2px;
56 | background-color: currentColor;
57 | opacity: .2;
58 | }
59 | .gsuiFxDelay-graph-source,
60 | .gsuiFxDelay-graph-echo {
61 | position: absolute;
62 | top: 50%;
63 | width: 10px;
64 | height: 10px;
65 | margin-top: -5px;
66 | margin-left: -5px;
67 | border-radius: 50%;
68 | background-color: currentColor;
69 | }
70 |
--------------------------------------------------------------------------------
/gsuiFxDelay/gsuiFxDelay.html.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | GSUsetTemplate( "gsui-fx-delay", () => [
4 | GSUcreateDiv( { class: "gsuiEffect-param-row", "data-prop": "time" },
5 | GSUcreateSpan( { class: "gsuiEffect-param-label" }, "time" ),
6 | GSUcreateElement( "gsui-slider", { type: "linear-x", step: .01, min: 0, max: 2 } ),
7 | GSUcreateSpan( { class: "gsuiEffect-param-value" } ),
8 | ),
9 | GSUcreateDiv( { class: "gsuiEffect-param-row", "data-prop": "gain" },
10 | GSUcreateSpan( { class: "gsuiEffect-param-label" }, "gain" ),
11 | GSUcreateElement( "gsui-slider", { type: "linear-x", step: .01, min: 0, max: .95 } ),
12 | GSUcreateSpan( { class: "gsuiEffect-param-value" } ),
13 | ),
14 | GSUcreateDiv( { class: "gsuiEffect-param-row", "data-prop": "pan" },
15 | GSUcreateSpan( { class: "gsuiEffect-param-label" }, "pan" ),
16 | GSUcreateElement( "gsui-slider", { type: "linear-x", step: .01, min: -1, max: 1 } ),
17 | GSUcreateSpan( { class: "gsuiEffect-param-value" } ),
18 | ),
19 | GSUcreateDiv( { class: "gsuiFxDelay-graph" },
20 | GSUcreateDiv( { class: "gsuiFxDelay-graph-lines" },
21 | GSUcreateElement( "gsui-beatlines", { timedivision: "4/4" } ),
22 | GSUcreateDiv( { class: "gsuiFxDelay-graph-line" } ),
23 | GSUcreateDiv( { class: "gsuiFxDelay-graph-source" } ),
24 | ),
25 | Array.from( { length: 20 }, ( _, n ) => GSUcreateDiv( { class: "gsuiFxDelay-graph-echo" } ) )
26 | ),
27 | ] );
28 |
--------------------------------------------------------------------------------
/gsuiFxDelay/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/gsuiFxFilter/gsuiFxFilter.html.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | GSUsetTemplate( "gsui-fx-filter", () => [
4 | GSUcreateDiv( { class: "gsuiFxFilter-area gsuiFxFilter-areaType" },
5 | GSUcreateSpan( { class: "gsuiEffect-param-label" }, "type" ),
6 | GSUcreateDiv( { class: "gsuiFxFilter-area-content" },
7 | GSUgetTemplate( "gsui-fx-filter-type", "lowpass", "M 1 4 L 12 4 L 15 8" ),
8 | GSUgetTemplate( "gsui-fx-filter-type", "highpass", "M 1 8 L 4 4 L 15 4" ),
9 | GSUgetTemplate( "gsui-fx-filter-type", "bandpass", "M 1 8 L 8 4 L 15 8" ),
10 | GSUgetTemplate( "gsui-fx-filter-type", "lowshelf", "M 1 8 L 4 8 L 6 4 L 15 4" ),
11 | GSUgetTemplate( "gsui-fx-filter-type", "highshelf", "M 1 4 L 10 4 L 12 8 L 15 8" ),
12 | GSUgetTemplate( "gsui-fx-filter-type", "peaking", "M 1 8 L 7 8 L 8 4 L 9 8 L 15 8" ),
13 | GSUgetTemplate( "gsui-fx-filter-type", "notch", "M 1 4 L 7 4 L 8 8 L 9 4 L 15 4" ),
14 | GSUgetTemplate( "gsui-fx-filter-type", "allpass", "M 1 6 L 15 6" ),
15 | ),
16 | ),
17 | GSUcreateDiv( { class: "gsuiFxFilter-area gsuiFxFilter-areaGraph" },
18 | GSUcreateSpan( { class: "gsuiEffect-param-label" }, "frequency" ),
19 | GSUcreateDiv( { class: "gsuiFxFilter-area-content" },
20 | GSUcreateElement( "gsui-curves" ),
21 | ),
22 | ),
23 | GSUcreateDiv( { class: "gsuiFxFilter-area gsuiFxFilter-areaFrequency" },
24 | GSUcreateDiv( { class: "gsuiFxFilter-area-content" },
25 | GSUcreateElement( "gsui-slider", { type: "linear-x", min: 0, max: 1, step: .001, "data-prop": "frequency" } ),
26 | ),
27 | ),
28 | GSUcreateDiv( { class: "gsuiFxFilter-area gsuiFxFilter-areaGain" },
29 | GSUcreateSpan( { class: "gsuiEffect-param-label" }, "gain" ),
30 | GSUcreateDiv( { class: "gsuiFxFilter-area-content" },
31 | GSUcreateElement( "gsui-slider", { type: "linear-y", min: -50, max: 50, step: .1, "mousemove-size": 400, "data-prop": "gain" } ),
32 | ),
33 | ),
34 | GSUcreateDiv( { class: "gsuiFxFilter-area gsuiFxFilter-areaQ" },
35 | GSUcreateSpan( { class: "gsuiEffect-param-label" }, "Q" ),
36 | GSUcreateDiv( { class: "gsuiFxFilter-area-content" },
37 | GSUcreateElement( "gsui-slider", { type: "circular", min: .001, max: 25, step: .001, "mousemove-size": 400, "data-prop": "Q" } ),
38 | ),
39 | ),
40 | GSUcreateDiv( { class: "gsuiFxFilter-area gsuiFxFilter-areaDetune" },
41 | GSUcreateSpan( { class: "gsuiEffect-param-label" }, "detune" ),
42 | GSUcreateDiv( { class: "gsuiFxFilter-area-content" },
43 | GSUcreateElement( "gsui-slider", { type: "circular", min: -1200, max: 1200, step: 10, "mousemove-size": 400, "data-prop": "detune" } ),
44 | ),
45 | ),
46 | ] );
47 |
48 | GSUsetTemplate( "gsui-fx-filter-type", ( type, d ) =>
49 | GSUcreateButton( { class: "gsuiFxFilter-areaType-btn", "data-type": type, title: type },
50 | GSUcreateElementSVG( "svg", { viewBox: "0 0 16 12" },
51 | GSUcreateElementSVG( "path", { d } ),
52 | ),
53 | )
54 | );
55 |
--------------------------------------------------------------------------------
/gsuiFxFilter/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/gsuiFxReverb/gsuiFxReverb.css:
--------------------------------------------------------------------------------
1 | gsui-fx-reverb {
2 | box-sizing: border-box;
3 | display: flex;
4 | flex-direction: column;
5 | height: 100%;
6 | min-width: 140px;
7 | min-height: 100px;
8 | gap: 8px;
9 | padding: 8px;
10 | --gsui-fadein-p: 0%;
11 | }
12 |
13 | /* .......................................................................... */
14 | gsui-fx-reverb .gsuiEffect-param-label {
15 | min-width: 40px;
16 | }
17 | gsui-fx-reverb gsui-slider {
18 | height: 10px;
19 | --gsuiSlider-lineColor: var( --gsui-col-gain );
20 | }
21 | gsui-fx-reverb .gsuiEffect-param-value {
22 | min-width: 52px;
23 | align-self: stretch;
24 | }
25 | gsui-fx-reverb .gsuiEffect-param-value::after {
26 | content: " %";
27 | }
28 | gsui-fx-reverb .gsuiEffect-param-row[ data-prop="delay" ] gsui-slider,
29 | gsui-fx-reverb .gsuiEffect-param-row[ data-prop="decay" ] gsui-slider,
30 | gsui-fx-reverb .gsuiEffect-param-row[ data-prop="fadein" ] gsui-slider {
31 | --gsuiSlider-lineColor: var( --gsui-col-time );
32 | }
33 | gsui-fx-reverb .gsuiEffect-param-row[ data-prop="delay" ] .gsuiEffect-param-value::after,
34 | gsui-fx-reverb .gsuiEffect-param-row[ data-prop="decay" ] .gsuiEffect-param-value::after,
35 | gsui-fx-reverb .gsuiEffect-param-row[ data-prop="fadein" ] .gsuiEffect-param-value::after {
36 | content: " b";
37 | }
38 |
39 | /* .......................................................................... */
40 | .gsuiFxReverb-graph {
41 | position: relative;
42 | overflow: hidden;
43 | flex: 1;
44 | min-height: 32px;
45 | border-radius: 6px;
46 | background-color: var( --gsui-screen-graph );
47 | }
48 | .gsuiFxReverb-graph-dry {
49 | position: absolute;
50 | inset: 20% auto 20% 0;
51 | width: 8px;
52 | border-radius: 2px;
53 | background-color: #ff9;
54 | }
55 | .gsuiFxReverb-graph-wet {
56 | position: absolute;
57 | inset: 15% auto 15% 0;
58 | width: 50%;
59 | border-radius: 2px;
60 | background-image: linear-gradient( 90deg, transparent, currentColor var( --gsui-fadein-p ), transparent );
61 | }
62 |
--------------------------------------------------------------------------------
/gsuiFxReverb/gsuiFxReverb.html.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | GSUsetTemplate( "gsui-fx-reverb", () => [
4 | GSUcreateDiv( { class: "gsuiEffect-param-row", "data-prop": "dry" },
5 | GSUcreateSpan( { class: "gsuiEffect-param-label" }, "dry" ),
6 | GSUcreateElement( "gsui-slider", { type: "linear-x", min: 0, max: 1, step: .01 } ),
7 | GSUcreateSpan( { class: "gsuiEffect-param-value" } ),
8 | ),
9 | GSUcreateDiv( { class: "gsuiEffect-param-row", "data-prop": "wet" },
10 | GSUcreateSpan( { class: "gsuiEffect-param-label" }, "wet" ),
11 | GSUcreateElement( "gsui-slider", { type: "linear-x", min: 0, max: 10, step: .01 } ),
12 | GSUcreateSpan( { class: "gsuiEffect-param-value" } ),
13 | ),
14 | GSUcreateDiv( { class: "gsuiEffect-param-row", "data-prop": "delay" },
15 | GSUcreateSpan( { class: "gsuiEffect-param-label" }, "delay" ),
16 | GSUcreateElement( "gsui-slider", { type: "linear-x", min: 0, max: 2, step: .01 } ),
17 | GSUcreateSpan( { class: "gsuiEffect-param-value" } ),
18 | ),
19 | GSUcreateDiv( { class: "gsuiEffect-param-row", "data-prop": "fadein" },
20 | GSUcreateSpan( { class: "gsuiEffect-param-label" }, "fadeIn" ),
21 | GSUcreateElement( "gsui-slider", { type: "linear-x", min: 0, max: 2, step: .01 } ),
22 | GSUcreateSpan( { class: "gsuiEffect-param-value" } ),
23 | ),
24 | GSUcreateDiv( { class: "gsuiEffect-param-row", "data-prop": "decay" },
25 | GSUcreateSpan( { class: "gsuiEffect-param-label" }, "decay" ),
26 | GSUcreateElement( "gsui-slider", { type: "linear-x", min: 0, max: 2, step: .01 } ),
27 | GSUcreateSpan( { class: "gsuiEffect-param-value" } ),
28 | ),
29 | GSUcreateDiv( { class: "gsuiFxReverb-graph" },
30 | GSUcreateElement( "gsui-beatlines", { timedivision: "4/4" } ),
31 | GSUcreateDiv( { class: "gsuiFxReverb-graph-wet" } ),
32 | GSUcreateDiv( { class: "gsuiFxReverb-graph-dry" } ),
33 | ),
34 | ] );
35 |
--------------------------------------------------------------------------------
/gsuiFxWaveShaper/gsuiFxWaveShaper.html.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | GSUsetTemplate( "gsui-fx-waveshaper", () => [
4 | GSUcreateDiv( { class: "gsuiFxWaveShaper-params" },
5 | GSUcreateDiv( { class: "gsuiFxWaveShaper-symmetry" },
6 | GSUcreateElement( "gsui-toggle", { off: true, "data-prop": "symmetry" } ),
7 | GSUcreateSpan( { class: "gsuiEffect-param-label" }, "symm" ),
8 | ),
9 | GSUcreateDiv( { class: "gsuiFxWaveShaper-oversample" },
10 | GSUcreateElement( "gsui-toggle", { off: true, "data-prop": "oversample" } ),
11 | GSUcreateSpan( { class: "gsuiEffect-param-label" }, "oversmp" ),
12 | GSUcreateSelect( { class: "gsuiEffect-param-value" },
13 | GSUcreateOption( { value: "2x" } ),
14 | GSUcreateOption( { value: "4x" } ),
15 | ),
16 | ),
17 | GSUcreateButton( { class: "gsuiFxWaveShaper-reset gsuiEffect-param-value" }, "reset" ),
18 | ),
19 | GSUcreateDiv( { class: "gsuiFxWaveShaper-in" },
20 | GSUcreateDiv( { class: "gsuiFxWaveShaper-side-graph" },
21 | GSUcreateDiv( { class: "gsuiFxWaveShaper-graph" },
22 | GSUcreateElementSVG( "svg", { class: "gsuiFxWaveShaper-graph-diag", preserveAspectRatio: "none", inert: true },
23 | GSUcreateElementSVG( "line" ),
24 | ),
25 | GSUcreateDiv( { class: "gsuiFxWaveShaper-graph-x", inert: true } ),
26 | GSUcreateDiv( { class: "gsuiFxWaveShaper-graph-y", inert: true } ),
27 | GSUcreateDiv( { class: "gsuiFxWaveShaper-graph-unit gsuiFxWaveShaper-graph-x-plus", inert: true } ),
28 | GSUcreateDiv( { class: "gsuiFxWaveShaper-graph-unit gsuiFxWaveShaper-graph-x-minus", inert: true } ),
29 | GSUcreateDiv( { class: "gsuiFxWaveShaper-graph-unit gsuiFxWaveShaper-graph-y-plus", inert: true } ),
30 | GSUcreateDiv( { class: "gsuiFxWaveShaper-graph-unit gsuiFxWaveShaper-graph-y-minus", inert: true } ),
31 | GSUcreateElement( "gsui-dotline", { viewbox: "-1 -1 1 1", xstep: .01, ystep: .01 } ),
32 | ),
33 | ),
34 | GSUcreateDiv( { class: "gsuiFxWaveShaper-side-waves" },
35 | GSUcreateElementSVG( "svg", { class: "gsuiFxWaveShaper-waves", preserveAspectRatio: "none", inert: true },
36 | GSUcreateElementSVG( "polyline", { class: "gsuiFxWaveShaper-waveA" } ),
37 | GSUcreateElementSVG( "polyline", { class: "gsuiFxWaveShaper-waveB" } ),
38 | ),
39 | ),
40 | ),
41 | ] );
42 |
--------------------------------------------------------------------------------
/gsuiGlitchText/gsuiGlitchText.css:
--------------------------------------------------------------------------------
1 | gsui-glitchtext {
2 | position: relative;
3 | color: #ccc;
4 | line-height: 1em;
5 | font-size: 68px;
6 | font-family: "oswald", monospace;
7 | }
8 | .gsuiGlitchText-blended {
9 | color: #fff;
10 | }
11 |
12 | /* .......................................................................... */
13 | .gsuiGlitchText-clip {
14 | position: relative;
15 | }
16 | .gsuiGlitchText-clip + .gsuiGlitchText-clip {
17 | position: absolute;
18 | top: 0;
19 | }
20 | .gsuiGlitchText:not( .gsuiGlitchText-blended ) .gsuiGlitchText-clip + .gsuiGlitchText-clip {
21 | display: none;
22 | }
23 |
24 | /* .......................................................................... */
25 | .gsuiGlitchText-word {
26 | margin: 0;
27 | white-space: nowrap;
28 | }
29 |
30 | /* .......................................................................... */
31 | .gsuiGlitchText-blend {
32 | position: absolute;
33 | top: 0;
34 | opacity: 0;
35 | transition: .1s;
36 | transition-property: opacity;
37 | }
38 | .gsuiGlitchText-blendA {
39 | color: #2af;
40 | margin: -.03em 0 0 .03em;
41 | mix-blend-mode: darken;
42 | }
43 | .gsuiGlitchText-blendB {
44 | color: #f64;
45 | margin: .03em 0 0 -.03em;
46 | mix-blend-mode: color-burn;
47 | }
48 | .gsuiGlitchText-blended .gsuiGlitchText-blend {
49 | opacity: .4;
50 | }
51 |
--------------------------------------------------------------------------------
/gsuiGlitchText/gsuiGlitchText.html.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | GSUsetTemplate( "gsui-glitchtext", () => [
4 | GSUgetTemplate( "gsui-glitchtext-layer" ),
5 | GSUgetTemplate( "gsui-glitchtext-layer" ),
6 | GSUgetTemplate( "gsui-glitchtext-layer" ),
7 | ] );
8 |
9 | GSUsetTemplate( "gsui-glitchtext-layer", () =>
10 | GSUcreateDiv( { class: "gsuiGlitchText-clip" },
11 | GSUcreateDiv( { class: "gsuiGlitchText-word" } ),
12 | GSUcreateDiv( { class: "gsuiGlitchText-word gsuiGlitchText-blend gsuiGlitchText-blendA" } ),
13 | GSUcreateDiv( { class: "gsuiGlitchText-word gsuiGlitchText-blend gsuiGlitchText-blendB" } ),
14 | )
15 | );
16 |
--------------------------------------------------------------------------------
/gsuiGlitchText/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
29 |
30 |
31 |
32 |
33 |
34 | GridSound
35 |
36 |
37 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
72 |
73 |
74 |
--------------------------------------------------------------------------------
/gsuiHelpLink/gsuiHelpLink.css:
--------------------------------------------------------------------------------
1 | [ gsuihelplink-hide ] gsui-help-link {
2 | display: none;
3 | }
4 | gsui-help-link {
5 | font-size: 14px;
6 | }
7 | gsui-help-link a {
8 | color: inherit;
9 | }
10 | gsui-help-link a::before,
11 | gsui-help-link a::after {
12 | color: var( --gsuiHelpLink-txt );
13 | }
14 | gsui-help-link a:hover::before {
15 | color: currentColor;
16 | }
17 |
--------------------------------------------------------------------------------
/gsuiHelpLink/gsuiHelpLink.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | class gsuiHelpLink extends gsui0ne {
4 | constructor() {
5 | super( {
6 | $cmpName: "gsuiHelpLink",
7 | $tagName: "gsui-help-link",
8 | $template: GSUcreateAExt( { class: "gsuiIcon", "data-icon": "info" } ),
9 | } );
10 | Object.seal( this );
11 | }
12 |
13 | // .........................................................................
14 | static get observedAttributes() {
15 | return [ "page" ];
16 | }
17 | $attributeChanged( prop, val ) {
18 | if ( prop === "page" ) {
19 | GSUsetAttribute( this.$element, {
20 | href: `https://github.com/gridsound/daw/wiki/help-${ val }`,
21 | title: `Open the ${ val } help page`,
22 | } );
23 | }
24 | }
25 | }
26 |
27 | GSUdefineElement( "gsui-help-link", gsuiHelpLink );
28 |
--------------------------------------------------------------------------------
/gsuiKeys/gsuiKeys.html.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | GSUsetTemplate( "gsui-keys-octave", () => [
4 | GSUcreateDiv( { class: "gsuiKeys-key", "data-key": 11 }, GSUcreateDiv( { class: "gsui-row gsuiKeys-row", "data-key": 11 }, GSUcreateDiv() ) ),
5 | GSUcreateDiv( { class: "gsuiKeys-key gsuiKeys-keyBlack", "data-key": 10 }, GSUcreateDiv( { class: "gsui-row gsuiKeys-row gsuiKeys-rowBlack", "data-key": 10 }, GSUcreateDiv() ) ),
6 | GSUcreateDiv( { class: "gsuiKeys-key", "data-key": 9 }, GSUcreateDiv( { class: "gsui-row gsuiKeys-row", "data-key": 9 }, GSUcreateDiv() ) ),
7 | GSUcreateDiv( { class: "gsuiKeys-key gsuiKeys-keyBlack", "data-key": 8 }, GSUcreateDiv( { class: "gsui-row gsuiKeys-row gsuiKeys-rowBlack", "data-key": 8 }, GSUcreateDiv() ) ),
8 | GSUcreateDiv( { class: "gsuiKeys-key", "data-key": 7 }, GSUcreateDiv( { class: "gsui-row gsuiKeys-row", "data-key": 7 }, GSUcreateDiv() ) ),
9 | GSUcreateDiv( { class: "gsuiKeys-key gsuiKeys-keyBlack", "data-key": 6 }, GSUcreateDiv( { class: "gsui-row gsuiKeys-row gsuiKeys-rowBlack", "data-key": 6 }, GSUcreateDiv() ) ),
10 | GSUcreateDiv( { class: "gsuiKeys-key", "data-key": 5 }, GSUcreateDiv( { class: "gsui-row gsuiKeys-row", "data-key": 5 }, GSUcreateDiv() ) ),
11 | GSUcreateDiv( { class: "gsuiKeys-key", "data-key": 4 }, GSUcreateDiv( { class: "gsui-row gsuiKeys-row", "data-key": 4 }, GSUcreateDiv() ) ),
12 | GSUcreateDiv( { class: "gsuiKeys-key gsuiKeys-keyBlack", "data-key": 3 }, GSUcreateDiv( { class: "gsui-row gsuiKeys-row gsuiKeys-rowBlack", "data-key": 3 }, GSUcreateDiv() ) ),
13 | GSUcreateDiv( { class: "gsuiKeys-key", "data-key": 2 }, GSUcreateDiv( { class: "gsui-row gsuiKeys-row", "data-key": 2 }, GSUcreateDiv() ) ),
14 | GSUcreateDiv( { class: "gsuiKeys-key gsuiKeys-keyBlack", "data-key": 1 }, GSUcreateDiv( { class: "gsui-row gsuiKeys-row gsuiKeys-rowBlack", "data-key": 1 }, GSUcreateDiv() ) ),
15 | GSUcreateDiv( { class: "gsuiKeys-key", "data-key": 0 }, GSUcreateDiv( { class: "gsui-row gsuiKeys-row", "data-key": 0 }, GSUcreateDiv() ) ),
16 | ] );
17 |
--------------------------------------------------------------------------------
/gsuiKeys/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/gsuiLFO/gsuiLFO.html.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | GSUsetTemplate( "gsui-lfo", () =>
4 | GSUcreateDiv( { class: "gsuiLFO-in" },
5 | GSUcreateDiv( { class: "gsuiLFO-props" },
6 | [
7 | [ "delay", "delay", "del", 0, 4, .03125 ],
8 | [ "attack", "attack", "att", 0, 4, .03125 ],
9 | [ "speed", "speed", "spd", .25, 18, .125 ],
10 | [ "amp", "amplitude", "amp", .001, 1, .001 ],
11 | ].map( ( [ prop, title, text, min, max, step ] ) =>
12 | GSUcreateDiv( { class: "gsuiLFO-prop", title, "data-prop": prop },
13 | GSUcreateSpan( { class: "gsuiLFO-propLabel" }, text ),
14 | GSUcreateSpan( { class: "gsuiLFO-propValue" } ),
15 | GSUcreateElement( "gsui-slider", { type: "linear-x", disabled: true, min, max, step, "mousemove-size": "800", "data-prop": prop } ),
16 | )
17 | ),
18 | ),
19 | GSUcreateDiv( { class: "gsuiLFO-type" },
20 | [
21 | [ "sine", "M 1 5 C 1 4 1 1 4 1 C 7 1 7 4 7 5 C 7 6 7 9 10 9 C 13 9 13 6 13 5" ],
22 | [ "triangle", "M 1 5 L 4 1 L 10 9 L 13 5" ],
23 | [ "sawtooth", "M 1 5 L 7 1 L 7 9 L 13 5" ],
24 | [ "square", "M 1 5 L 1 1 L 7 1 L 7 9 L 13 9 L 13 5" ],
25 | ].map( ( [ w, dots ] ) =>
26 | GSUcreateLabel( { class: "gsuiLFO-btn gsuiLFO-typeBtn", title: w },
27 | GSUcreateInput( { class: "gsuiLFO-btnInput gsuiLFO-typeRadio", name: "gsuiLFO-type", type: "radio", value: w } ),
28 | GSUcreateElementSVG( "svg", { class: "gsuiLFO-btnIcon gsuiLFO-typeSVG", viewBox: "0 0 14 10" }, GSUcreateElementSVG( "path", { d: dots } ) ),
29 | )
30 | ),
31 | ),
32 | GSUcreateDiv( { class: "gsuiLFO-graph" },
33 | GSUcreateDiv( { class: "gsuiLFO-wave" },
34 | GSUcreateElement( "gsui-beatlines", { coloredbeats: "" } ),
35 | GSUcreateElement( "gsui-periodicwave" ),
36 | GSUcreateDiv( { class: "gsuiLFO-keyPreviews" } ),
37 | ),
38 | GSUcreateDiv( { class: "gsuiLFO-ampSigns" },
39 | GSUcreateLabel( { class: "gsuiLFO-btn gsuiLFO-ampSign" },
40 | GSUcreateInput( { class: "gsuiLFO-btnInput gsuiLFO-ampSignRadio", name: "gsuiLFO-ampSign", type: "radio", value: "1" } ),
41 | GSUcreateIcon( { class: "gsuiLFO-btnIcon gsuiLFO-ampSignIcon", icon: "caret-up" } ),
42 | ),
43 | GSUcreateLabel( { class: "gsuiLFO-btn gsuiLFO-ampSign" },
44 | GSUcreateInput( { class: "gsuiLFO-btnInput gsuiLFO-ampSignRadio", name: "gsuiLFO-ampSign", type: "radio", value: "-1" } ),
45 | GSUcreateIcon( { class: "gsuiLFO-btnIcon gsuiLFO-ampSignIcon", icon: "caret-down" } ),
46 | ),
47 | ),
48 | ),
49 | )
50 | );
51 |
--------------------------------------------------------------------------------
/gsuiLibraries/gsuiLibraries.css:
--------------------------------------------------------------------------------
1 | gsui-libraries {
2 | display: flex;
3 | flex-direction: column;
4 | height: 100%;
5 | }
6 |
7 | /* .......................................................................... */
8 | .gsuiLibraries-head {
9 | display: flex;
10 | align-items: center;
11 | gap: 4px;
12 | height: 24px;
13 | min-height: 24px;
14 | line-height: 1;
15 | padding: 0 6px;
16 | font-size: 11px;
17 | background-color: var( --gsui-head2-bg );
18 | }
19 | .gsuiLibraries-head-icon,
20 | .gsuiLibraries-head-title {
21 | font-weight: bold;
22 | opacity: .7;
23 | }
24 |
25 | /* .......................................................................... */
26 | .gsuiLibraries-libBtns {
27 | display: flex;
28 | margin-left: 8px;
29 | border-radius: 4px;
30 | background-color: #0004;
31 | overflow: hidden;
32 | }
33 | .gsuiLibraries-libBtn {
34 | display: flex;
35 | align-items: center;
36 | height: 18px;
37 | border: 0;
38 | outline: 0;
39 | padding: 1px 3px 0 6px;
40 | font: inherit;
41 | font-size: 9px;
42 | font-weight: bold;
43 | cursor: pointer;
44 | background-color: transparent;
45 | }
46 | .gsuiLibraries-libBtn + .gsuiLibraries-libBtn {
47 | padding-left: 3px;
48 | }
49 | .gsuiLibraries-libBtn:last-child {
50 | padding-right: 6px;
51 | }
52 | gsui-libraries:not( [ lib="default" ] ) .gsuiLibraries-libBtn[ data-lib="default" ],
53 | gsui-libraries:not( [ lib="local" ] ) .gsuiLibraries-libBtn[ data-lib="local" ] {
54 | opacity: .3;
55 | }
56 |
57 | /* .......................................................................... */
58 | .gsuiLibraries-body {
59 | position: relative;
60 | flex: 1;
61 | }
62 | .gsuiLibraries-body gsui-library {
63 | position: absolute;
64 | inset: 0;
65 | }
66 | gsui-libraries:not( [ lib="default" ] ) .gsuiLibrary-default,
67 | gsui-libraries:not( [ lib="local" ] ) .gsuiLibrary-local {
68 | display: none;
69 | }
70 |
--------------------------------------------------------------------------------
/gsuiLibraries/gsuiLibraries.html.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | GSUsetTemplate( "gsui-libraries", () => [
4 | GSUcreateDiv( { class: "gsuiLibraries-head" },
5 | GSUcreateIcon( { class: "gsuiLibraries-head-icon", icon: "waveform" } ),
6 | GSUcreateSpan( { class: "gsuiLibraries-head-title" }, "library" ),
7 | GSUcreateDiv( { class: "gsuiLibraries-libBtns" },
8 | GSUcreateButton( { class: "gsuiLibraries-libBtn", "data-lib": "default" }, "default" ),
9 | GSUcreateButton( { class: "gsuiLibraries-libBtn", "data-lib": "local" }, "local" ),
10 | ),
11 | ),
12 | GSUcreateDiv( { class: "gsuiLibraries-body" },
13 | GSUcreateElement( "gsui-library", { class: "gsuiLibrary-default" } ),
14 | GSUcreateElement( "gsui-library", { class: "gsuiLibrary-local" } ),
15 | ),
16 | ] );
17 |
--------------------------------------------------------------------------------
/gsuiLibraries/gsuiLibraries.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | class gsuiLibraries extends gsui0ne {
4 | constructor() {
5 | super( {
6 | $cmpName: "gsuiLibraries",
7 | $tagName: "gsui-libraries",
8 | $elements: {
9 | $libBtns: ".gsuiLibraries-libBtns",
10 | $libDef: ".gsuiLibrary-default",
11 | $libLoc: ".gsuiLibrary-local",
12 | },
13 | $attributes: {
14 | lib: "default",
15 | },
16 | } );
17 | Object.seal( this );
18 | this.$elements.$libBtns.onclick = gsuiLibraries.#onclickBtns.bind( null, this );
19 | this.$elements.$libDef.$setPlaceholder( "loading..." );
20 | this.$elements.$libLoc.$setPlaceholder( "drag'n drop your own samples in the app, they will appear here" );
21 | }
22 |
23 | // .........................................................................
24 | $getLibrary( lib ) {
25 | return lib === "local" ? this.$elements.$libLoc : this.$elements.$libDef;
26 | }
27 |
28 | // .........................................................................
29 | static #onclickBtns( root, e ) {
30 | if ( e.target.dataset.lib ) {
31 | GSUsetAttribute( root, "lib", e.target.dataset.lib );
32 | }
33 | }
34 | }
35 |
36 | GSUdefineElement( "gsui-libraries", gsuiLibraries );
37 |
--------------------------------------------------------------------------------
/gsuiLibrary/gsuiLibrary.html.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | GSUsetTemplate( "gsui-library", () => [
4 | GSUcreateDiv( { class: "gsuiLibrary-head" } ),
5 | GSUcreateDiv( { class: "gsuiLibrary-body" },
6 | GSUcreateDiv( { class: "gsuiLibrary-placeholder" }, "no sample here..." ),
7 | ),
8 | ] );
9 |
10 | GSUsetTemplate( "gsui-library-sep", id =>
11 | GSUcreateDiv( { class: "gsuiLibrary-sep gsuiLibrary-sep-expanded", "data-id": id, title: id },
12 | GSUcreateButton( { class: "gsuiLibrary-sep-btn", tabindex: -1 },
13 | GSUcreateIcon( { icon: "caret-right" } ),
14 | GSUcreateSpan( null, id ),
15 | ),
16 | )
17 | );
18 |
19 | GSUsetTemplate( "gsui-library-sample", obj =>
20 | GSUcreateDiv( { class: "gsuiLibrary-sample gsuiLibrary-sample-expanded", "data-id": obj.id, "data-name": obj.name, title: obj.name },
21 | GSUcreateDiv( { class: "gsuiLibrary-sample-wave", inert: true },
22 | GSUcreateElementSVG( "svg", { class: "gsuiLibrary-sample-svg", viewBox: "0 0 40 10", preserveAspectRatio: "none" },
23 | GSUcreateElementSVG( "polygon", { class: "gsuiLibrary-sample-poly", points: obj.points } ),
24 | ),
25 | ),
26 | )
27 | );
28 |
--------------------------------------------------------------------------------
/gsuiLibrary/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
75 |
76 |
77 |
--------------------------------------------------------------------------------
/gsuiMixer/gsuiMixer.css:
--------------------------------------------------------------------------------
1 | gsui-mixer {
2 | position: relative;
3 | z-index: 0;
4 | display: flex;
5 | height: 100%;
6 | min-width: 400px;
7 | min-height: 200px;
8 | }
9 |
10 | /* .......................................................................... */
11 | .gsuiMixer-channels {
12 | display: flex;
13 | flex-direction: column;
14 | flex: 1;
15 | min-width: 140px;
16 | }
17 | .gsuiMixer-effects {
18 | display: flex;
19 | flex-direction: column;
20 | width: 50%;
21 | min-width: 250px;
22 | border-left: 2px solid var( --gsui-head3-brd );
23 | }
24 |
25 | /* .......................................................................... */
26 | .gsuiMixer-head {
27 | box-sizing: border-box;
28 | display: flex;
29 | align-items: center;
30 | gap: 6px;
31 | height: 26px;
32 | min-height: 26px;
33 | padding: 2px 6px 0;
34 | font-size: 10px;
35 | border-bottom: 2px solid var( --gsui-head3-brd );
36 | background-color: var( --gsui-head3-bg );
37 | }
38 | .gsuiMixer-head-title {
39 | font-weight: bold;
40 | }
41 |
42 | /* .......................................................................... */
43 | .gsuiMixer-bottomShadow {
44 | position: absolute;
45 | top: 100%;
46 | width: 100%;
47 | height: 50px;
48 | }
49 |
50 | /* .......................................................................... */
51 | .gsuiMixer-analyserTypes {
52 | margin-left: 10px;
53 | display: flex;
54 | gap: 4px;
55 | opacity: .8;
56 | }
57 | .gsuiMixer-analyserTypes > .gsuiIcon {
58 | font-size: 13px;
59 | }
60 | .gsuiMixer-analyserTypes-labels {
61 | display: flex;
62 | flex-direction: column;
63 | cursor: pointer;
64 | }
65 |
66 | /* .......................................................................... */
67 | .gsuiMixer-analyserTypes-label {
68 | display: flex;
69 | align-items: center;
70 | height: 9px;
71 | gap: .5ch;
72 | font-size: 8px;
73 | }
74 | .gsuiMixer-analyserTypes-label span { opacity: .7 }
75 | .gsuiMixer-analyserTypes-label .gsuiIcon::after { opacity: .3 }
76 | .gsuiMixer-analyserTypes-label .gsuiIcon::before { opacity: 0 }
77 | gsui-mixer[ analyser="td" ] .gsuiMixer-analyserTypes-label:first-child .gsuiIcon::before,
78 | gsui-mixer[ analyser="hz" ] .gsuiMixer-analyserTypes-label:last-child .gsuiIcon::before,
79 | gsui-mixer[ analyser="td" ] .gsuiMixer-analyserTypes-label:first-child span,
80 | gsui-mixer[ analyser="hz" ] .gsuiMixer-analyserTypes-label:last-child span {
81 | opacity: 1;
82 | }
83 |
--------------------------------------------------------------------------------
/gsuiMixer/gsuiMixer.html.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | GSUsetTemplate( "gsui-mixer", () =>
4 | GSUcreateElement( "gsui-panels", { dir: "x" },
5 | GSUcreateDiv( { class: "gsuiMixer-channels" },
6 | GSUcreateDiv( { class: "gsuiMixer-head" },
7 | GSUcreateIcon( { class: "gsuiMixer-head-icon", icon: "channels" } ),
8 | GSUcreateSpan( { class: "gsuiMixer-head-title", inert: true }, "channels" ),
9 | GSUcreateElement( "gsui-help-link", { page: "mixer-channels" } ),
10 | GSUcreateDiv( { class: "gsuiMixer-analyserTypes" },
11 | GSUcreateIcon( { icon: "waveform" } ),
12 | GSUcreateDiv( { class: "gsuiMixer-analyserTypes-labels" },
13 | GSUgetTemplate( "gsui-mixer-analyser-label", "timeDomain" ),
14 | GSUgetTemplate( "gsui-mixer-analyser-label", "frequency" ),
15 | ),
16 | ),
17 | ),
18 | GSUcreateElement( "gsui-channels" ),
19 | ),
20 | GSUcreateDiv( { class: "gsuiMixer-effects" },
21 | GSUcreateDiv( { class: "gsuiMixer-head" },
22 | GSUcreateIcon( { class: "gsuiMixer-head-icon", icon: "effects" } ),
23 | GSUcreateSpan( { class: "gsuiMixer-head-title", inert: true }, "effects" ),
24 | GSUcreateElement( "gsui-help-link", { page: "mixer-effects" } ),
25 | ),
26 | GSUcreateElement( "gsui-effects" ),
27 | GSUcreateDiv( { class: "gsuiMixer-bottomShadow", inert: true } ),
28 | ),
29 | ),
30 | );
31 |
32 | GSUsetTemplate( "gsui-mixer-analyser-label", txt =>
33 | GSUcreateDiv( { class: "gsuiMixer-analyserTypes-label", inert: true },
34 | GSUcreateIcon( { icon: "radio-btn-checked" } ),
35 | GSUcreateSpan( null, txt ),
36 | )
37 | );
38 |
--------------------------------------------------------------------------------
/gsuiMixer/gsuiMixer.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | class gsuiMixer extends gsui0ne {
4 | #shadowChans = null;
5 | #shadowEffects = null;
6 |
7 | constructor() {
8 | super( {
9 | $cmpName: "gsuiMixer",
10 | $tagName: "gsui-mixer",
11 | $elements: {
12 | $channels: "gsui-channels",
13 | $effects: "gsui-effects",
14 | $analyserType: ".gsuiMixer-analyserTypes-labels",
15 | },
16 | $attributes: {
17 | analyser: "hz",
18 | },
19 | } );
20 | Object.seal( this );
21 | this.$elements.$analyserType.onclick = () => {
22 | const type = GSUgetAttribute( this, "analyser" ) === "hz" ? "td" : "hz";
23 |
24 | GSUsetAttribute( this, "analyser", type );
25 | this.$dispatch( "changeAnalyser", type );
26 | };
27 | GSUlistenEvents( this, {
28 | gsuiChannels: {
29 | nbChannelsChange: () => {
30 | this.#shadowChans.$update();
31 | },
32 | },
33 | gsuiEffect: {
34 | expand: () => {
35 | GSUsetTimeout( () => this.#shadowEffects.$update(), .1 );
36 | },
37 | },
38 | } );
39 | }
40 |
41 | // .........................................................................
42 | $connected() {
43 | this.#shadowChans = new gsuiScrollShadow( {
44 | scrolledElem: this.querySelector( ".gsuiChannels-panChannels" ),
45 | leftShadow: this.querySelector( ".gsuiChannels-panMain" ),
46 | rightShadow: this.querySelector( ".gsuiMixer-effects" ),
47 | } );
48 | this.#shadowEffects = new gsuiScrollShadow( {
49 | scrolledElem: this.$elements.$effects,
50 | topShadow: this.querySelector( ".gsuiMixer-effects .gsuiMixer-head" ),
51 | bottomShadow: this.querySelector( ".gsuiMixer-effects .gsuiMixer-bottomShadow" ),
52 | } );
53 | }
54 | $disconnected() {
55 | this.#shadowChans.$disconnected();
56 | this.#shadowEffects.$disconnected();
57 | }
58 | static get observedAttributes() {
59 | return [ "analyser" ];
60 | }
61 | $attributeChanged( prop, val ) {
62 | switch ( prop ) {
63 | case "analyser":
64 | this.$elements.$channels.$setAnalyserType( val );
65 | break;
66 | }
67 | }
68 |
69 | // .........................................................................
70 | $getChannels() { return this.$elements.$channels; }
71 | $getEffects() { return this.$elements.$effects; }
72 | }
73 |
74 | GSUdefineElement( "gsui-mixer", gsuiMixer );
75 |
--------------------------------------------------------------------------------
/gsuiNoise/gsuiNoise.css:
--------------------------------------------------------------------------------
1 | gsui-noise {
2 | box-sizing: border-box;
3 | display: flex;
4 | align-items: center;
5 | min-width: 380px;
6 | gap: 8px;
7 | padding: 6px 10px;
8 | font-size: 12px;
9 | border-top: var( --gsui-item-brdtop );
10 | border-bottom: var( --gsui-item-brdbottom );
11 | background-color: var( --gsui-item-bg );
12 | }
13 |
14 | /* .......................................................................... */
15 | .gsuiNoise-type-txt,
16 | gsui-noise > span {
17 | opacity: .5;
18 | }
19 |
20 | /* .......................................................................... */
21 | .gsuiNoise-type {
22 | position: relative;
23 | display: flex;
24 | align-items: center;
25 | width: 92px;
26 | gap: 4px;
27 | }
28 | .gsuiNoise-type-color {
29 | width: 10px;
30 | height: 10px;
31 | border: 1px solid #000c;
32 | border-radius: 3px;
33 | }
34 | gsui-noise:not( [ toggle ] ) .gsuiNoise-type-color {
35 | opacity: .3;
36 | }
37 | gsui-noise[ color="white" ] .gsuiNoise-type-color { background-color: #fff }
38 | gsui-noise[ color="pink" ] .gsuiNoise-type-color { background-color: #b04565 }
39 | gsui-noise[ color="brown" ] .gsuiNoise-type-color { background-color: #bd6c40 }
40 | .gsuiNoise-type-txt::after {
41 | content: " noise";
42 | }
43 | .gsuiNoise-type-select {
44 | position: absolute;
45 | width: 100%;
46 | opacity: 0;
47 | cursor: pointer;
48 | }
49 | gsui-noise:not( [ toggle ] ) .gsuiNoise-type-select {
50 | cursor: not-allowed;
51 | }
52 |
53 | /* .......................................................................... */
54 | .gsuiNoise-value {
55 | width: 27px;
56 | font-family: var( --gsui-font-number );
57 | }
58 |
59 | /* .......................................................................... */
60 | gsui-noise gsui-slider {
61 | height: 8px;
62 | }
63 | gsui-noise .gsuiSlider-eventCatcher {
64 | inset: -10px -8px;
65 | }
66 | gsui-noise gsui-slider[ data-prop="gain" ] {
67 | width: 80px;
68 | --gsuiSlider-lineColor: var( --gsui-col-gain );
69 | }
70 | gsui-noise gsui-slider[ data-prop="pan" ] {
71 | width: 50px;
72 | --gsuiSlider-lineColor: var( --gsui-col-pan );
73 | }
--------------------------------------------------------------------------------
/gsuiNoise/gsuiNoise.html.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | GSUsetTemplate( "gsui-noise", txt => [
4 | GSUcreateDiv( { class: "gsuiNoise-type" },
5 | GSUcreateDiv( { class: "gsuiNoise-type-color" } ),
6 | GSUcreateSpan( { class: "gsuiNoise-type-txt" }, "white" ),
7 | GSUcreateSelect( { class: "gsuiNoise-type-select" },
8 | GSUcreateOption( { value: "white" } ),
9 | GSUcreateOption( { value: "pink" } ),
10 | GSUcreateOption( { value: "brown" } ),
11 | ),
12 | ),
13 | GSUcreateElement( "gsui-slider", { "data-prop": "gain", type: "linear-x", min: 0, max: 1, step: .005, "mousemove-size": 400 } ),
14 | GSUcreateSpan( { class: "gsuiNoise-value", "data-prop": "gain" } ),
15 | GSUcreateSpan( null, "pan" ),
16 | GSUcreateElement( "gsui-slider", { "data-prop": "pan", type: "linear-x", min: -1, max: 1, step: .01, "mousemove-size": 400, defaultValue: 0 } ),
17 | GSUcreateSpan( { class: "gsuiNoise-value", "data-prop": "pan" } ),
18 | ] );
19 |
--------------------------------------------------------------------------------
/gsuiNoise/gsuiNoise.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | class gsuiNoise extends gsui0ne {
4 | constructor() {
5 | super( {
6 | $cmpName: "gsuiNoise",
7 | $tagName: "gsui-noise",
8 | $elements: {
9 | $values: {
10 | gain: ".gsuiNoise-value[data-prop=gain]",
11 | pan: ".gsuiNoise-value[data-prop=pan]",
12 | },
13 | $sliders: {
14 | gain: "gsui-slider[data-prop=gain]",
15 | pan: "gsui-slider[data-prop=pan]",
16 | },
17 | $colorTxt: ".gsuiNoise-type-txt",
18 | $colorSelect: ".gsuiNoise-type select",
19 | },
20 | $attributes: {
21 | toggle: false,
22 | color: "white",
23 | gain: 0,
24 | pan: 0,
25 | },
26 | } );
27 | Object.seal( this );
28 | this.$elements.$colorSelect.onkeydown = GSUnoopFalse;
29 | this.$elements.$colorSelect.onchange = () => {
30 | const col = this.$elements.$colorSelect.value;
31 |
32 | GSUsetAttribute( this, "color", col );
33 | this.$dispatch( "change", "color", col );
34 | };
35 | GSUlistenEvents( this, {
36 | gsuiSlider: {
37 | inputStart: GSUnoop,
38 | inputEnd: GSUnoop,
39 | input: ( d, t ) => {
40 | this.#setValue( t.dataset.prop, d.args[ 0 ] );
41 | this.$dispatch( "input", t.dataset.prop, d.args[ 0 ] );
42 | },
43 | change: ( d, t ) => {
44 | this.$dispatch( "change", t.dataset.prop, d.args[ 0 ] );
45 | },
46 | },
47 | } );
48 | }
49 |
50 | // .........................................................................
51 | static get observedAttributes() {
52 | return [ "toggle", "color", "gain", "pan" ];
53 | }
54 | $attributeChanged( prop, val ) {
55 | switch ( prop ) {
56 | case "toggle":
57 | GSUsetAttribute( this.$elements.$sliders.gain, "disabled", val === null );
58 | GSUsetAttribute( this.$elements.$sliders.pan, "disabled", val === null );
59 | GSUsetAttribute( this.$elements.$colorSelect, "disabled", val === null );
60 | break;
61 | case "color":
62 | this.$elements.$colorTxt.textContent = val;
63 | this.$elements.$colorSelect.value = val;
64 | break;
65 | case "gain":
66 | case "pan":
67 | this.#setValue( prop, val );
68 | GSUsetAttribute( this.$elements.$sliders[ prop ], "value", val );
69 | break;
70 | }
71 | }
72 |
73 | // .........................................................................
74 | #setValue( prop, val ) {
75 | const val2 = Math.round( val * 100 );
76 | const val3 = prop === "pan"
77 | ? GSUmathSign( val2 )
78 | : val2;
79 |
80 | this.$elements.$values[ prop ].textContent = `${ val3 }%`;
81 | }
82 | }
83 |
84 | GSUdefineElement( "gsui-noise", gsuiNoise );
85 |
--------------------------------------------------------------------------------
/gsuiNoise/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
64 |
65 |
66 |
--------------------------------------------------------------------------------
/gsuiPanels/gsuiPanels.css:
--------------------------------------------------------------------------------
1 | gsui-panels {
2 | position: relative;
3 | overflow: hidden;
4 | display: flex;
5 | width: 100%;
6 | height: 100%;
7 | }
8 | gsui-panels[ dir="y" ] {
9 | flex-direction: column;
10 | }
11 |
12 | /* .......................................................................... */
13 | .gsuiPanels-panel {
14 | position: absolute;
15 | box-sizing: border-box;
16 | width: 100%;
17 | height: 100%;
18 | }
19 |
20 | /* .......................................................................... */
21 | .gsuiPanels-extend {
22 | position: absolute;
23 | width: 100%;
24 | height: 100%;
25 | transition: background-color .2s;
26 | }
27 | gsui-panels[ dir="x" ] > .gsuiPanels-panel > .gsuiPanels-extend {
28 | top: 0;
29 | left: -2px;
30 | width: 4px;
31 | cursor: col-resize;
32 | }
33 | gsui-panels[ dir="y" ] > .gsuiPanels-panel > .gsuiPanels-extend {
34 | left: 0;
35 | top: -2px;
36 | height: 4px;
37 | cursor: row-resize;
38 | }
39 |
--------------------------------------------------------------------------------
/gsuiPanels/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/gsuiPatternroll/gsuiPatternroll.css:
--------------------------------------------------------------------------------
1 | gsui-patternroll {
2 | display: flex;
3 | height: 100%;
4 | }
5 |
6 | gsui-patternroll gsui-track {
7 | height: var( --gsuiTimewindow-lineH );
8 | }
9 |
10 | .gsuiPatternroll-block {
11 | container: gsuiPatternroll-block-query / inline-size;
12 | box-sizing: border-box;
13 | white-space: nowrap;
14 | color: var( --gsuiPatterns-pattern-color );
15 | border-radius: 2px;
16 | border-top: 2px solid #ffffff4f;
17 | border-bottom: 2px solid #0000001f;
18 | border-left: 2px solid #ffffff69;
19 | border-right: 1px solid #00000033;
20 | box-shadow: 0 0 0px 1px #00000047;
21 | --gsuiPatterns-pattern-color: #223;
22 | }
23 | .gsui-mute .gsuiPatternroll-block {
24 | opacity: .6;
25 | }
26 | .gsuiPatternroll-block-header {
27 | position: absolute;
28 | inset: 3px 3px auto;
29 | box-sizing: border-box;
30 | z-index: 1;
31 | display: flex;
32 | border-radius: inherit;
33 | flex-direction: column;
34 | justify-content: center;
35 | padding: 0 4px;
36 | font-size: 10px;
37 | font-weight: bold;
38 | background-color: #fff3;
39 | pointer-events: none;
40 | }
41 | .gsuiPatternroll-block-name {
42 | overflow: hidden;
43 | text-overflow: ellipsis;
44 | }
45 | .gsuiPatternroll-block-content {
46 | position: absolute;
47 | inset: 18px 0 0;
48 | pointer-events: none;
49 | }
50 | .gsuiPatternroll-block[ data-missing ] .gsuiPatternroll-block-content {
51 | display: none;
52 | }
53 | .gsuiPatternroll-block-content svg {
54 | position: absolute;
55 | top: 0;
56 | left: 0;
57 | width: 100%;
58 | height: 100%;
59 | opacity: .8;
60 | fill: currentColor;
61 | }
62 |
63 | .gsui-row-small .gsuiPatternroll-block-header {
64 | background-color: inherit;
65 | }
66 | .gsui-row-small .gsuiPatternroll-block-header,
67 | .gsui-row-small .gsuiPatternroll-block-content {
68 | position: absolute;
69 | inset: 0;
70 | }
71 |
72 | .gsuiPatternroll-block-placeholder {
73 | flex: 1;
74 | display: none;
75 | align-items: center;
76 | pointer-events: none;
77 | font-size: 14px;
78 | opacity: .5;
79 | }
80 | .gsuiPatternroll-block[ data-missing ] .gsuiPatternroll-block-placeholder {
81 | display: flex;
82 | }
83 | .gsuiPatternroll-block-placeholderIcon {
84 | margin: 0 8px;
85 | }
86 | .gsuiPatternroll-block-placeholderText {
87 | overflow: hidden;
88 | text-overflow: ellipsis;
89 | }
90 |
91 | /* .......................................................................... */
92 | @container gsuiPatternroll-block-query ( max-width: 32px ) {
93 | .gsuiPatternroll-block-name {
94 | display: none;
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/gsuiPatternroll/gsuiPatternroll.html.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | GSUsetTemplate( "gsui-patternroll-block", () =>
4 | GSUcreateDiv( { class: "gsuiBlocksManager-block gsuiPatternroll-block", "data-action": "move" },
5 | GSUcreateDiv( { class: "gsuiBlocksManager-block-crop gsuiBlocksManager-block-cropA", "data-action": "cropA" } ),
6 | GSUcreateDiv( { class: "gsuiBlocksManager-block-crop gsuiBlocksManager-block-cropB", "data-action": "cropB" } ),
7 | GSUcreateDiv( { class: "gsuiPatternroll-block-header" },
8 | GSUcreateSpan( { class: "gsuiPatternroll-block-name" } ),
9 | ),
10 | GSUcreateDiv( { class: "gsuiPatternroll-block-content" } ),
11 | GSUcreateDiv( { class: "gsuiPatternroll-block-placeholder" },
12 | GSUcreateIcon( { class: "gsuiPatternroll-block-placeholderIcon", icon: "file-corrupt" } ),
13 | GSUcreateSpan( { class: "gsuiPatternroll-block-placeholderText" }, "missing data" ),
14 | ),
15 | )
16 | );
17 |
--------------------------------------------------------------------------------
/gsuiPatterns/gsuiPatterns-infoPopup.html.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | GSUsetTemplate( "gsui-patterns-infoPopup", () =>
4 | GSUcreateDiv( { id: "gsuiPatterns-infoPopupContent" },
5 | GSUcreateElement( "fieldset", null,
6 | GSUcreateElement( "legend", null, "Type" ),
7 | GSUcreateLabel( null,
8 | GSUcreateInput( { type: "radio", name: "type", value: "drum" } ),
9 | GSUcreateIcon( { icon: "buf-drum" } ),
10 | GSUcreateSpan( null, "drum" ),
11 | ),
12 | GSUcreateLabel( null,
13 | GSUcreateInput( { type: "radio", name: "type", value: "fx" } ),
14 | GSUcreateIcon( { icon: "buf-fx" } ),
15 | GSUcreateSpan( null, "fx" ),
16 | ),
17 | GSUcreateLabel( null,
18 | GSUcreateInput( { type: "radio", name: "type", value: "vocal" } ),
19 | GSUcreateIcon( { icon: "buf-vocal" } ),
20 | GSUcreateSpan( null, "vocal" ),
21 | ),
22 | GSUcreateLabel( null,
23 | GSUcreateInput( { type: "radio", name: "type", value: "loop" } ),
24 | GSUcreateIcon( { icon: "buf-loop" } ),
25 | GSUcreateSpan( null, "loop" ),
26 | GSUcreateSpan( null, "bpm" ),
27 | GSUcreateInput( { class: "gsuiPopup-inputText", type: "number", name: "bpm", min: 1, max: 999.99, step: .01 } ),
28 | ),
29 | ),
30 | GSUcreateElement( "fieldset", null,
31 | GSUcreateElement( "legend", null, "Edit" ),
32 | GSUcreateLabel( null,
33 | GSUcreateInput( { type: "checkbox", name: "reverse" } ),
34 | GSUcreateIcon( { icon: "reverse" } ),
35 | GSUcreateSpan( null, "reverse" ),
36 | ),
37 | ),
38 | GSUcreateElement( "fieldset", null,
39 | GSUcreateElement( "legend", null, "Name" ),
40 | GSUcreateLabel( null,
41 | GSUcreateInput( { class: "gsuiPopup-inputText", type: "text", name: "name" } ),
42 | ),
43 | ),
44 | )
45 | );
46 |
--------------------------------------------------------------------------------
/gsuiPatterns/gsuiPatterns-pattern.html.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | GSUsetTemplate( "gsui-patterns-pattern", () =>
4 | GSUcreateDiv( { class: "gsuiPatterns-pattern" },
5 | GSUcreateDiv( { class: "gsuiPatterns-pattern-grip gsuiIcon", "data-icon": "grip-v" } ),
6 | GSUcreateDiv( { class: "gsuiPatterns-pattern-head" },
7 | GSUcreateDiv( { class: "gsuiPatterns-pattern-info" },
8 | GSUcreateButton( { class: "gsuiPatterns-pattern-btn gsuiPatterns-pattern-btnInfo", "data-action": "editInfo", icon: "buf-undefined", title: "Edit buffer's info" } ),
9 | GSUcreateDiv( { class: "gsuiPatterns-pattern-name" } ),
10 | GSUcreateButton( { class: "gsuiPatterns-btnSolid gsuiPatterns-pattern-dest", "data-action": "redirect", title: "Redirect this pattern" },
11 | GSUcreateIcon( { class: "gsuiPatterns-btnIcon", icon: "mixer" } ),
12 | GSUcreateSpan( { class: "gsuiPatterns-btnText" } ),
13 | ),
14 | ),
15 | GSUcreateButton( { class: "gsuiPatterns-pattern-btn", "data-action": "clone", icon: "clone", title: "Clone this pattern" } ),
16 | GSUcreateButton( { class: "gsuiPatterns-pattern-btn", "data-action": "remove", icon: "close", title: "Delete this pattern" } ),
17 | ),
18 | GSUcreateDiv( { class: "gsuiPatterns-pattern-content" } ),
19 | GSUcreateDiv( { class: "gsuiPatterns-pattern-placeholder" },
20 | GSUcreateIcon( { class: "gsuiPatterns-pattern-placeholderIcon", icon: "file-corrupt" } ),
21 | GSUcreateSpan( { class: "gsuiPatterns-pattern-placeholderText" }, "missing data" ),
22 | ),
23 | )
24 | );
25 |
--------------------------------------------------------------------------------
/gsuiPatterns/gsuiPatterns-synth.html.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | GSUsetTemplate( "gsui-patterns-synth", () =>
4 | GSUcreateDiv( { class: "gsuiPatterns-synth" },
5 | GSUcreateDiv( { class: "gsuiPatterns-synth-head" },
6 | GSUcreateButton( { class: "gsuiPatterns-synth-btn gsuiPatterns-synth-expand", "data-action": "expand", icon: "caret-right" } ),
7 | GSUcreateDiv( { class: "gsuiPatterns-synth-info" },
8 | GSUcreateDiv( { class: "gsuiPatterns-synth-name" } ),
9 | GSUcreateButton( { class: "gsuiPatterns-btnSolid gsuiPatterns-synth-dest", "data-action": "redirect", title: "Redirect this synthesizer" },
10 | GSUcreateIcon( { class: "gsuiPatterns-btnIcon", icon: "mixer" } ),
11 | GSUcreateSpan( { class: "gsuiPatterns-btnText" } ),
12 | ),
13 | ),
14 | GSUcreateButton( { class: "gsuiPatterns-synth-btn", "data-action": "newPattern", icon: "plus", title: "Create a new pattern with this synthesizer" } ),
15 | GSUcreateButton( { class: "gsuiPatterns-synth-btn", "data-action": "delete", icon: "close", title: "Delete the synthesizer and its patterns" } ),
16 | ),
17 | GSUcreateDiv( { class: "gsuiPatterns-placeholderToCheck gsuiPatterns-synth-patterns" },
18 | GSUcreateDiv( { class: "gsuiPatterns-placeholder", inert: true },
19 | GSUcreateSpan( null, "this synthesizer has no related pattern" ),
20 | ),
21 | ),
22 | )
23 | );
24 |
--------------------------------------------------------------------------------
/gsuiPatterns/gsuiPatterns.html.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | GSUsetTemplate( "gsui-patterns", () =>
4 | GSUcreateElement( "gsui-panels", { dir: "y" },
5 | GSUgetTemplate( "gsui-patterns-panel", {
6 | type: "buffers",
7 | title: "buffers",
8 | icon: "waveform",
9 | placeholder: "drag 'n drop raw files here (mp3, ogg, wav)",
10 | } ),
11 | GSUgetTemplate( "gsui-patterns-panel", {
12 | type: "slices",
13 | title: "slices",
14 | icon: "slices",
15 | placeholder: "no slices yet",
16 | button: { action: "newSlices", title: "Create a new slices pattern" },
17 | } ),
18 | GSUgetTemplate( "gsui-patterns-panel", {
19 | type: "drums",
20 | title: "drums",
21 | icon: "drums",
22 | placeholder: "no drums yet",
23 | button: { action: "newDrums", title: "Create a new drums pattern" },
24 | } ),
25 | GSUgetTemplate( "gsui-patterns-panel", {
26 | type: "keys",
27 | title: "keys",
28 | icon: "oscillator",
29 | placeholder: "no synth yet",
30 | button: { action: "newSynth", title: "Create a new synthesizer" },
31 | } ),
32 | )
33 | );
34 |
35 | GSUsetTemplate( "gsui-patterns-panel", obj =>
36 | GSUcreateDiv( { class: "gsuiPatterns-panel", "data-type": obj.type },
37 | GSUcreateDiv( { class: "gsuiPatterns-panel-menu" },
38 | GSUcreateIcon( { class: "gsuiPatterns-panel-icon", icon: obj.icon } ),
39 | GSUcreateSpan( { class: "gsuiPatterns-panel-title" }, obj.title ),
40 | obj.button && GSUcreateButton( { class: "gsuiPatterns-btnSolid", "data-action": obj.button.action, title: obj.button.title },
41 | GSUcreateIcon( { class: "gsuiPatterns-btnIcon", icon: "plus" } ),
42 | ),
43 | ),
44 | GSUcreateDiv( { class: "gsuiPatterns-panel-list-wrap" },
45 | GSUcreateDiv( { class: "gsuiPatterns-placeholderToCheck gsuiPatterns-panel-list" } ),
46 | GSUcreateDiv( { class: "gsuiPatterns-placeholder", inert: true },
47 | GSUcreateSpan( null, obj.placeholder ),
48 | ),
49 | ),
50 | )
51 | );
52 |
--------------------------------------------------------------------------------
/gsuiPeriodicWave/gsuiPeriodicWave.css:
--------------------------------------------------------------------------------
1 | gsui-periodicwave,
2 | gsui-periodicwave svg {
3 | width: 100%;
4 | height: 100%;
5 | }
6 | gsui-periodicwave polyline {
7 | stroke: currentColor;
8 | fill: none;
9 | }
10 |
--------------------------------------------------------------------------------
/gsuiPianoroll/gsuiPianoroll-block.css:
--------------------------------------------------------------------------------
1 | .gsuiPianoroll-block {
2 | container: gsuiPianoroll-block-query / size;
3 | --gsuiDragline-color: var( --gsuiBlocksManager-blockColor );
4 | }
5 |
6 | /* .......................................................................... */
7 | .gsuiPianoroll-block-key {
8 | position: absolute;
9 | display: flex;
10 | align-items: center;
11 | left: 4px;
12 | height: 100%;
13 | color: #000;
14 | font-size: 11px;
15 | font-weight: bold;
16 | opacity: .4;
17 | pointer-events: none;
18 | }
19 |
20 | /* .......................................................................... */
21 | .gsuiPianoroll-block .gsuiDragline {
22 | top: 50%;
23 | right: 0;
24 | }
25 |
26 | /* .......................................................................... */
27 | .gsuiPianoroll-block .gsuiDragline-drop {
28 | top: 50%;
29 | left: 0;
30 | }
31 | .gsuiPianoroll-block .gsuiDragline-drop::before {
32 | left: 0;
33 | }
34 | .gsuiPianoroll-block .gsuiDragline-dropActive::before {
35 | left: -4px;
36 | }
37 |
38 | /* .......................................................................... */
39 | .gsuiPianoroll-block:not( :hover ):not( .gsui-hover ) .gsuiDragline:not( .gsuiDragline-dragging ) .gsuiDragline-to {
40 | background-color: transparent;
41 | }
42 | .gsuiPianoroll-block:hover .gsuiDragline:not( .gsuiDragline-linked ) .gsuiDragline-to,
43 | .gsuiPianoroll-block.gsui-hover .gsuiDragline:not( .gsuiDragline-linked ) .gsuiDragline-to {
44 | transform: translateX( 2px );
45 | }
46 | .gsuiPianoroll-block:hover .gsuiDragline-linked .gsuiDragline-to,
47 | .gsuiPianoroll-block.gsui-hover .gsuiDragline-linked .gsuiDragline-to {
48 | transform: translateX( -2px );
49 | }
50 |
51 | /* .......................................................................... */
52 | @container gsuiPianoroll-block-query ( max-width: 24px ) {
53 | .gsuiPianoroll-block-key {
54 | display: none;
55 | }
56 | }
57 | @container gsuiPianoroll-block-query ( max-height: 14px ) {
58 | .gsuiPianoroll-block-key {
59 | font-size: 10px;
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/gsuiPianoroll/gsuiPianoroll.css:
--------------------------------------------------------------------------------
1 | gsui-pianoroll {
2 | display: flex;
3 | height: 100%;
4 | --gsuiDragline-dotSize: 10px;
5 | --gsuiDragline-dotRad: 2px;
6 | --gsuiDragline-lineSize: 3px;
7 | }
8 | gsui-pianoroll:focus {
9 | outline: 1px solid var( --gsuiBlocksManager-blockColor );
10 | }
11 |
12 | /* .......................................................................... */
13 | gsui-pianoroll gsui-keys {
14 | font-size: var( --gsuiTimewindow-lineH );
15 | }
16 | gsui-pianoroll .gsuiTimewindow-rows {
17 | font-size: var( --gsuiTimewindow-lineH );
18 | }
19 | gsui-pianoroll .gsuiKeys-row > div {
20 | font-size: var( --gsuiTimewindow-pxperbeat );
21 | }
22 | gsui-pianoroll gsui-prop-select {
23 | position: absolute;
24 | inset: 0;
25 | padding: 6px 0;
26 | }
27 |
28 | /* .......................................................................... */
29 | gsui-pianoroll .gsuiBlocksManager-block {
30 | border-radius: 2px;
31 | }
32 |
33 | /* .......................................................................... */
34 | gsui-pianoroll .gsuiTimewindow-panelContentDown {
35 | display: flex;
36 | align-items: center;
37 | justify-content: center;
38 | }
39 | .gsuiPianoroll-slidersSelect {
40 | border: 0;
41 | outline: 0;
42 | font: inherit;
43 | color: inherit;
44 | cursor: pointer;
45 | font-size: 11px;
46 | border-radius: 4px;
47 | background-color: #fff2;
48 | scrollbar-width: none;
49 | opacity: .5;
50 | transition: .1s opacity;
51 | }
52 | .gsuiPianoroll-slidersSelect::-webkit-scrollbar {
53 | display: none;
54 | }
55 | .gsuiPianoroll-slidersSelect:focus,
56 | .gsuiPianoroll-slidersSelect:hover {
57 | opacity: 1;
58 | }
59 | .gsuiPianoroll-slidersSelect option {
60 | padding: 1px 4px;
61 | }
62 | .gsuiPianoroll-slidersSelect option::after {
63 | content: attr( data-number );
64 | margin-left: 1ch;
65 | font-size: 14px;
66 | font-weight: bold;
67 | font-family: var( --gsui-font-number );
68 | }
69 | .gsuiPianoroll-slidersSelect option[ value^="gainLFO" ]::after {
70 | content: "x" attr( data-number );
71 | }
72 | .gsuiPianoroll-slidersSelect option:not( [ data-number ] )::after {
73 | content: "";
74 | }
75 |
--------------------------------------------------------------------------------
/gsuiPianoroll/gsuiPianoroll.html.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | GSUsetTemplate( "gsui-pianoroll-block", () =>
4 | GSUcreateDiv( { class: "gsuiBlocksManager-block gsuiPianoroll-block", "data-action": "move" },
5 | GSUcreateDiv( { class: "gsuiPianoroll-block-key" } ),
6 | GSUcreateDiv( { class: "gsuiDragline-drop" } ),
7 | GSUcreateDiv( { class: "gsuiBlocksManager-block-crop gsuiBlocksManager-block-cropB", "data-action": "cropB" } ),
8 | )
9 | );
10 |
--------------------------------------------------------------------------------
/gsuiPopup/gsuiPopup.html.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | GSUsetTemplate( "gsui-popup", () => [
4 | GSUcreateDiv( { class: "gsuiPopup-overlay" } ),
5 | GSUcreateDiv( { class: "gsuiPopup-window", tabindex: 0 },
6 | GSUcreateDiv( { class: "gsuiPopup-head" } ),
7 | GSUcreateElement( "form", { class: "gsuiPopup-body" },
8 | GSUcreateDiv( { class: "gsuiPopup-content" } ),
9 | GSUcreateDiv( { class: "gsuiPopup-message" } ),
10 | GSUcreateInput( { class: "gsuiPopup-inputText", type: "text" } ),
11 | GSUcreateDiv( { class: "gsuiPopup-btns" },
12 | GSUcreateElement( "gsui-com-button", { class: "gsuiPopup-cancel", text: "Cancel" } ),
13 | GSUcreateElement( "gsui-com-button", { class: "gsuiPopup-ok", text: "Ok", type: "submit" } ),
14 | ),
15 | ),
16 | )
17 | ] );
18 |
--------------------------------------------------------------------------------
/gsuiPropSelect/gsuiPropSelect.css:
--------------------------------------------------------------------------------
1 | gsui-prop-select {
2 | overflow: auto;
3 | display: flex;
4 | flex-wrap: wrap;
5 | align-content: safe center;
6 | justify-content: center;
7 | box-sizing: border-box;
8 | gap: 3px;
9 | line-height: 18px;
10 | }
11 |
12 | /* .......................................................................... */
13 | .gsuiPropSelect-sep {
14 | flex-basis: 100%;
15 | height: 18px;
16 | font-size: 11px;
17 | text-align: center;
18 | opacity: .5;
19 | }
20 |
21 | /* .......................................................................... */
22 | .gsuiPropSelect-btn {
23 | outline: 0;
24 | height: 18px;
25 | border: 1px dashed;
26 | border-radius: 3px;
27 | padding: 0 6px;
28 | font-size: 11px;
29 | font-weight: bold;
30 | cursor: pointer;
31 | }
32 | .gsuiPropSelect-btn[ data-prop="gainLFOSpeed" ],
33 | .gsuiPropSelect-btn[ data-prop="gainLFOAmp" ],
34 | .gsuiPropSelect-btn[ data-prop="gain" ] { color: var( --gsui-col-gain ) }
35 | .gsuiPropSelect-btn[ data-prop="pan" ] { color: var( --gsui-col-pan ) }
36 | .gsuiPropSelect-btn[ data-prop="detune" ] { color: var( --gsui-col-detune ) }
37 | .gsuiPropSelect-btn[ data-prop="lowpass" ] { color: var( --gsui-col-lowpass ) }
38 | .gsuiPropSelect-btn[ data-prop="highpass" ] { color: var( --gsui-col-highpass ) }
39 | .gsuiPropSelect-btn:hover {
40 | background-color: #fff1;
41 | }
42 | .gsuiPropSelect-btn[ data-selected ] {
43 | background-color: currentColor;
44 | }
45 | .gsuiPropSelect-btn[ data-value ]::before {
46 | content: attr( data-value );
47 | color: #333;
48 | font-size: 14px;
49 | font-family: var( --gsui-font-number );
50 | }
51 | .gsuiPropSelect-btn:not( [ data-value ] )::before {
52 | content: attr( data-label );
53 | }
54 | .gsuiPropSelect-btn[ data-selected ]:not( [ data-value ] )::before {
55 | color: #333;
56 | }
57 |
--------------------------------------------------------------------------------
/gsuiPropSelect/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/gsuiReorder/gsuiReorder.css:
--------------------------------------------------------------------------------
1 | .gsuiReorder-dragging.gsuiReorder-reordering {
2 | opacity: .2 !important;
3 | }
4 |
5 | /* .......................................................................... */
6 | .gsuiReorder-dropArea {
7 | position: relative;
8 | }
9 | .gsuiReorder-dropArea::after {
10 | content: "";
11 | position: absolute;
12 | z-index: 1;
13 | inset: 0;
14 | border-radius: inherit;
15 | background-color: transparent;
16 | opacity: .3;
17 | animation: gsuiReorder-dropArea-anim .5s forwards ease;
18 | animation-delay: inherit;
19 | }
20 | .gsuiReorder-dropArea-hover::after {
21 | opacity: 1;
22 | }
23 | @keyframes gsuiReorder-dropArea-anim {
24 | 0% { background-color: transparent }
25 | 20% { background-color: #1e90ff }
26 | 100% { background-color: #1e90ff50 }
27 | }
28 |
29 | /* .......................................................................... */
30 | #gsuiReorder-fake {
31 | z-index: 1;
32 | position: absolute;
33 | overflow: hidden;
34 | box-sizing: border-box;
35 | width: 60px;
36 | height: 60px;
37 | color: var( --gsuiReorder-skeleton-txt );
38 | border: 2px solid;
39 | pointer-events: none;
40 | }
41 | #gsuiReorder-fake::before,
42 | #gsuiReorder-fake-grip::before {
43 | content: "";
44 | position: absolute;
45 | inset: 0;
46 | background-color: currentColor;
47 | opacity: .2;
48 | }
49 | #gsuiReorder-fake-grip {
50 | position: absolute;
51 | box-sizing: border-box;
52 | border: inherit;
53 | margin: -2px;
54 | }
55 | #gsuiReorder-fake-grip::before {
56 | opacity: .4;
57 | }
58 |
--------------------------------------------------------------------------------
/gsuiRipple/gsuiRipple.css:
--------------------------------------------------------------------------------
1 | .gsuiRipple {
2 | position: relative;
3 | overflow: hidden;
4 | }
5 | .gsuiRipple-circle {
6 | position: absolute;
7 | margin: -60%;
8 | width: 120%;
9 | padding-top: 120%;
10 | border-radius: 50%;
11 | background-color: #fff;
12 | opacity: .6;
13 | transform: scale( 0 );
14 | transition-duration: 0s;
15 | pointer-events: none;
16 | }
17 | .gsuiRipple-active .gsuiRipple-circle {
18 | transform: scale( 2 );
19 | opacity: 0;
20 | transition-duration: .7s;
21 | transition-property: opacity, transform;
22 | }
23 |
--------------------------------------------------------------------------------
/gsuiRipple/gsuiRipple.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | class gsuiRipple {
4 | static #map = new Map();
5 | static #spaceDown = false;
6 |
7 | static $init( el ) {
8 | el.classList.add( "gsuiRipple" );
9 | el.addEventListener( "pointerdown", gsuiRipple.#ptrdown, false );
10 | el.addEventListener( "keydown", gsuiRipple.#keydown, false );
11 | el.addEventListener( "keyup", gsuiRipple.#keyup, false );
12 | gsuiRipple.#map.set( el, {} );
13 | }
14 |
15 | static #keydown( e ) {
16 | if ( e.key === " " && !gsuiRipple.#spaceDown ) {
17 | gsuiRipple.#spaceDown = true;
18 | gsuiRipple.#exec( e, .5, .5 );
19 | }
20 | }
21 | static #keyup( e ) {
22 | if ( e.key === " " ) {
23 | gsuiRipple.#spaceDown = false;
24 | }
25 | }
26 | static #ptrdown( e ) {
27 | const el = e.currentTarget;
28 | const bcr = el.getBoundingClientRect();
29 |
30 | gsuiRipple.#exec( e,
31 | ( e.clientX - bcr.left ) / bcr.width,
32 | ( e.clientY - bcr.top ) / bcr.height,
33 | );
34 | }
35 | static #exec( e, x, y ) {
36 | const el = e.currentTarget;
37 | const obj = gsuiRipple.#map.get( el );
38 | const circ = GSUcreateSpan( { class: "gsuiRipple-circle", style: {
39 | left: `${ x * 100 }%`,
40 | top: `${ y * 100 }%`,
41 | } } );
42 |
43 | GSUclearTimeout( obj.$timeoutId );
44 | if ( obj.$elCirc ) {
45 | obj.$elCirc.remove();
46 | }
47 | obj.$elCirc = circ;
48 | el.prepend( circ );
49 | el.classList.remove( "gsuiRipple-active" );
50 | obj.$timeoutId = GSUsetTimeout( () => {
51 | el.classList.add( "gsuiRipple-active" );
52 | obj.$timeoutId = GSUsetTimeout( () => {
53 | el.classList.remove( "gsuiRipple-active" );
54 | circ.remove();
55 | }, .7 );
56 | }, .1 );
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/gsuiSVGPatterns/gsuiSVGPatternsAutomation.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | class gsuiSVGPatternsAutomation {
4 | static $render( data, dur ) {
5 | const poly = GSUcreateElementSVG( "polyline" );
6 |
7 | GSUsetAttribute( poly, "points", gsuiDotlineSVG.$draw( data, dur * 1, 1, dur, 1, 0, 0 ) );
8 | return [ poly ];
9 | }
10 | }
11 |
12 | Object.freeze( gsuiSVGPatternsAutomation );
13 |
--------------------------------------------------------------------------------
/gsuiSVGPatterns/gsuiSVGPatternsDrums.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | class gsuiSVGPatternsDrums {
4 | static $render( drums, drumrows, sPB ) {
5 | const rowsArr = Object.entries( drumrows );
6 | const drmW = 1 / sPB;
7 | const drmH = 1 / rowsArr.length;
8 | const orders = rowsArr
9 | .sort( ( a, b ) => a[ 1 ].order - b[ 1 ].order )
10 | .reduce( ( obj, [ id ], i ) => {
11 | obj[ id ] = i;
12 | return obj;
13 | }, {} );
14 |
15 | return Object.values( drums )
16 | .map( d => ( "gain" in d
17 | ? gsuiSVGPatternsDrums.#createDrum
18 | : gsuiSVGPatternsDrums.#createDrumcut )( d.when, orders[ d.row ] * drmH, drmW, drmH ) );
19 | }
20 | static #createDrum( x, y, w, h ) {
21 | return GSUcreateElementSVG( "polygon", {
22 | points: GSUmathFix( [ x, y, x, y + h * .75, x + w, y + h * .75 / 2 ], 3 ).join( "," ),
23 | } );
24 | }
25 | static #createDrumcut( x, y, w, h ) {
26 | return GSUcreateElementSVG( "rect", {
27 | x: GSUmathFix( x, 3 ),
28 | y: GSUmathFix( y + h * .8, 3 ),
29 | width: GSUmathFix( w * .9, 3 ),
30 | height: GSUmathFix( h * .2, 3 ),
31 | } );
32 | }
33 | }
34 |
35 | Object.freeze( gsuiSVGPatternsDrums );
36 |
--------------------------------------------------------------------------------
/gsuiSVGPatterns/gsuiSVGPatternsKeys.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | class gsuiSVGPatternsKeys {
4 | static $render( keys ) {
5 | const arrKeys = Object.values( keys );
6 | const { min, size } = gsuiSVGPatternsKeys.#calcMinMax( arrKeys );
7 | const rowH = GSUmathFix( 1 / ( size + 1 ), 3 );
8 |
9 | return arrKeys.map( k => GSUcreateElementSVG( "rect", {
10 | x: GSUmathFix( k.when, 3 ),
11 | y: GSUmathFix( ( size - k.key + min ) * rowH, 3 ),
12 | width: GSUmathFix( k.duration, 3 ),
13 | height: rowH,
14 | } ) );
15 | }
16 | static #calcMinMax( arrKeys ) {
17 | let min = Infinity;
18 | let max = -Infinity;
19 |
20 | arrKeys.forEach( k => {
21 | min = Math.min( min, k.key );
22 | max = Math.max( max, k.key );
23 | } );
24 | min -= min % 12;
25 | max += 11 - max % 12;
26 | return { min, size: max - min };
27 | }
28 | }
29 |
30 | Object.freeze( gsuiSVGPatternsKeys );
31 |
--------------------------------------------------------------------------------
/gsuiSVGPatterns/gsuiSVGPatternsSlices.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | class gsuiSVGPatternsSlices {
4 | static $render( slices, dur ) {
5 | return Object.values( slices ).map( sli => [
6 | gsuiSVGPatternsSlices.#renderSliceRect( sli, dur, null ),
7 | gsuiSVGPatternsSlices.#renderSliceRect( sli, dur, .25 ),
8 | ] ).flat( 1 );
9 | }
10 | static #renderSliceRect( { x, y, w }, dur, opacity ) {
11 | return GSUcreateElementSVG( "rect", {
12 | x: dur * x,
13 | y,
14 | opacity,
15 | width: dur * ( w - .005 ),
16 | height: opacity === null ? .05 : 1 - y,
17 | } );
18 | }
19 | }
20 |
21 | Object.freeze( gsuiSVGPatternsSlices );
22 |
--------------------------------------------------------------------------------
/gsuiScrollShadow/gsuiScrollShadow.css:
--------------------------------------------------------------------------------
1 | .gsuiScrollShadow {
2 | --gsuiScrollShadow-dist: 0;
3 | --gsuiScrollShadow-x: 0;
4 | --gsuiScrollShadow-y: 0;
5 | z-index: 1;
6 | }
7 | .gsuiScrollShadow[ data-dir='top' ] { --gsuiScrollShadow-y: 1; }
8 | .gsuiScrollShadow[ data-dir='left' ] { --gsuiScrollShadow-x: 1; }
9 | .gsuiScrollShadow[ data-dir='right' ] { --gsuiScrollShadow-x: -1; }
10 | .gsuiScrollShadow[ data-dir='bottom' ] { --gsuiScrollShadow-y: -1; }
11 | .gsuiScrollShadow-shadowed {
12 | box-shadow:
13 | calc( var( --gsuiScrollShadow-dist ) * var( --gsuiScrollShadow-x ) )
14 | calc( var( --gsuiScrollShadow-dist ) * var( --gsuiScrollShadow-y ) )
15 | calc( var( --gsuiScrollShadow-dist ) * 2 )
16 | #0004;
17 | }
18 |
--------------------------------------------------------------------------------
/gsuiScrollShadow/gsuiScrollShadow.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | class gsuiScrollShadow {
4 | #scrolledElem = null;
5 | #topShadow = null;
6 | #leftShadow = null;
7 | #rightShadow = null;
8 | #bottomShadow = null;
9 | #onscrollBind = this.#onscroll.bind( this );
10 |
11 | constructor( o ) {
12 | Object.seal( this );
13 | this.#scrolledElem = o.scrolledElem;
14 | this.#topShadow = o.topShadow ? [ o.topShadow ].flat() : [];
15 | this.#leftShadow = o.leftShadow ? [ o.leftShadow ].flat() : [];
16 | this.#rightShadow = o.rightShadow ? [ o.rightShadow ].flat() : [];
17 | this.#bottomShadow = o.bottomShadow ? [ o.bottomShadow ].flat() : [];
18 | gsuiScrollShadow.#initShadow( this.#topShadow, "top" );
19 | gsuiScrollShadow.#initShadow( this.#leftShadow, "left" );
20 | gsuiScrollShadow.#initShadow( this.#rightShadow, "right" );
21 | gsuiScrollShadow.#initShadow( this.#bottomShadow, "bottom" );
22 | this.#scrolledElem.addEventListener( "scroll", this.#onscrollBind );
23 | GSUobserveSizeOf( this.#scrolledElem, this.#onscrollBind );
24 | }
25 |
26 | // .........................................................................
27 | $disconnected() {
28 | GSUunobserveSizeOf( this.#scrolledElem, this.#onscrollBind );
29 | }
30 |
31 | // .........................................................................
32 | $update() {
33 | this.#onscroll();
34 | }
35 | static #initShadow( elems, dir ) {
36 | elems.forEach( el => {
37 | el.classList.add( "gsuiScrollShadow" );
38 | el.dataset.dir = dir;
39 | } );
40 | }
41 | #onscroll() {
42 | const el = this.#scrolledElem;
43 |
44 | gsuiScrollShadow.#onscroll2( this.#topShadow, el.scrollTop );
45 | gsuiScrollShadow.#onscroll2( this.#leftShadow, el.scrollLeft );
46 | gsuiScrollShadow.#onscroll2( this.#rightShadow, el.scrollWidth - el.clientWidth - el.scrollLeft );
47 | gsuiScrollShadow.#onscroll2( this.#bottomShadow, el.scrollHeight - el.clientHeight - el.scrollTop );
48 | }
49 | static #onscroll2( elems, scroll ) {
50 | elems.forEach( el => {
51 | GSUsetStyle( el, "--gsuiScrollShadow-dist", `${ Math.min( scroll / 5, 5 ) }px` );
52 | el.classList.toggle( "gsuiScrollShadow-shadowed", scroll > 0 );
53 | } );
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/gsuiSlicer/gsuiSlicer.html.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | GSUsetTemplate( "gsui-slicer", () => [
4 | GSUcreateDiv( { class: "gsuiSlicer-source" },
5 | GSUcreateDiv( { class: "gsuiSlicer-source-head" },
6 | GSUcreateIcon( { class: "gsuiSlicer-source-icon", icon: "waveform" } ),
7 | GSUcreateSpan( { class: "gsuiSlicer-source-name" } ),
8 | ),
9 | GSUcreateDiv( { class: "gsuiSlicer-source-sample-wrap" },
10 | GSUcreateDiv( { class: "gsuiSlicer-source-sample" },
11 | GSUcreateElementSVG( "svg", { class: "gsuiSlicer-source-wave", viewBox: "0 0 1000 64", preserveAspectRatio: "none" },
12 | GSUcreateElementSVG( "polyline" ),
13 | ),
14 | GSUcreateDiv( { class: "gsuiSlicer-currentTime gsuiSlicer-source-currentTime" } ),
15 | ),
16 | ),
17 | ),
18 | GSUcreateDiv( { class: "gsuiSlicer-time" },
19 | GSUcreateElement( "gsui-timeline" ),
20 | ),
21 | GSUcreateDiv( { class: "gsuiSlicer-preview" },
22 | GSUcreateDiv( { class: "gsuiSlicer-currentTime gsuiSlicer-preview-currentTime" } ),
23 | ),
24 | GSUcreateDiv( { class: "gsuiSlicer-slices" },
25 | GSUcreateDiv( { class: "gsuiSlicer-slices-scroll" },
26 | GSUcreateDiv( { class: "gsuiSlicer-slices-in" },
27 | GSUcreateDiv( { class: "gsuiSlicer-slices-beatlinesWrap" },
28 | GSUcreateElement( "gsui-beatlines" ),
29 | GSUcreateElement( "gsui-beatlines", { vertical: true } ),
30 | ),
31 | GSUcreateDiv( { class: "gsuiSlicer-currentTime gsuiSlicer-slices-currentTime" } ),
32 | GSUcreateElementSVG( "svg", { class: "gsuiSlicer-slices-line", preserveAspectRatio: "none" },
33 | GSUcreateElementSVG( "line" ),
34 | ),
35 | GSUcreateDiv( { class: "gsuiSlicer-slices-wrap" } ),
36 | ),
37 | ),
38 | ),
39 | GSUcreateDiv( { class: "gsuiSlicer-menu" },
40 | GSUcreateElement( "gsui-step-select" ),
41 | GSUcreateButton( { class: "gsuiSlicer-btn", "data-action": "moveY", icon: "hand-pointer", title: "Move slices vertically" } ),
42 | GSUcreateButton( { class: "gsuiSlicer-btn", "data-action": "reset", icon: "slices", title: "Reset slices vertically" } ),
43 | GSUcreateButton( { class: "gsuiSlicer-btn", "data-action": "split", icon: "cut", title: "Cut slices in half" } ),
44 | GSUcreateButton( { class: "gsuiSlicer-btn", "data-action": "merge", icon: "erase", title: "Merge slices together" } ),
45 | ),
46 | ] );
47 |
--------------------------------------------------------------------------------
/gsuiSlider/gsuiSlider.css:
--------------------------------------------------------------------------------
1 | gsui-slider {
2 | --gsuiSlider-lineColor2: var( --gsuiSlider-lineColor );
3 | display: block;
4 | position: relative;
5 | width: 100%;
6 | height: 100%;
7 | outline: 0;
8 | touch-action: none;
9 | }
10 | gsui-slider[ disabled ] {
11 | --gsuiSlider-lineColor2: var( --gsuiSlider-lineColor-disabled );
12 | cursor: not-allowed;
13 | }
14 |
15 | .gsuiSlider-line,
16 | .gsuiSlider-eventCatcher {
17 | position: absolute;
18 | inset: 0;
19 | }
20 |
21 | .gsuiSlider-linear .gsuiSlider-svg,
22 | .gsuiSlider-circular .gsuiSlider-line {
23 | display: none;
24 | }
25 |
26 | .gsuiSlider-line {
27 | overflow: hidden;
28 | border-radius: var( --gsuiSlider-lineRadius, 2px );
29 | background-color: var( --gsuiSlider-lineBgColor );
30 | }
31 | .gsuiSlider-lineColor {
32 | position: absolute;
33 | background-color: var( --gsuiSlider-lineColor2 );
34 | }
35 |
36 | .gsuiSlider-svg {
37 | position: absolute;
38 | width: 100%;
39 | height: 100%;
40 | pointer-events: none;
41 | }
42 | .gsuiSlider-svgLine,
43 | .gsuiSlider-svgLineColor {
44 | fill: none;
45 | transform-origin: center;
46 | }
47 | .gsuiSlider-svgLine { stroke: var( --gsuiSlider-lineBgColor ); }
48 | .gsuiSlider-svgLineColor { stroke: var( --gsuiSlider-lineColor2 ); }
49 |
--------------------------------------------------------------------------------
/gsuiSlider/gsuiSlider.html.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | GSUsetTemplate( "gsui-slider", () => [
4 | GSUcreateDiv( { class: "gsuiSlider-line" },
5 | GSUcreateDiv( { class: "gsuiSlider-lineColor" } ),
6 | ),
7 | GSUcreateElementSVG( "svg", { class: "gsuiSlider-svg" },
8 | GSUcreateElementSVG( "circle", { class: "gsuiSlider-svgLine" } ),
9 | GSUcreateElementSVG( "circle", { class: "gsuiSlider-svgLineColor" } ),
10 | ),
11 | GSUcreateDiv( { class: "gsuiSlider-eventCatcher" } ),
12 | ] );
13 |
--------------------------------------------------------------------------------
/gsuiSliderGroup/gsuiSliderGroup.css:
--------------------------------------------------------------------------------
1 | gsui-slidergroup {
2 | display: block;
3 | position: relative;
4 | overflow: hidden;
5 | height: 100%;
6 | z-index: 0;
7 | }
8 | .gsuiSliderGroup-slidersWrap {
9 | position: absolute;
10 | width: 100%;
11 | top: 0;
12 | bottom: 0;
13 | overflow: auto;
14 | scrollbar-width: none;
15 | }
16 | .gsuiSliderGroup-slidersWrap::-webkit-scrollbar {
17 | display: none;
18 | }
19 | .gsuiSliderGroup-sliders {
20 | position: absolute;
21 | width: 1000000px;
22 | height: 100%;
23 | }
24 |
25 | /* .......................................................................... */
26 | .gsuiSliderGroup-slider {
27 | position: absolute;
28 | overflow: hidden;
29 | top: 0;
30 | bottom: 0;
31 | cursor: pointer;
32 | }
33 | .gsuiSliderGroup-slider::before {
34 | content: "";
35 | position: absolute;
36 | height: 100%;
37 | width: 6px;
38 | background-color: #0002;
39 | }
40 | gsui-slidergroup:has( .gsuiSliderGroup-sliderSelected ) .gsuiSliderGroup-slider:not( .gsuiSliderGroup-sliderSelected ) {
41 | pointer-events: none;
42 | }
43 | .gsuiSliderGroup-sliderInner {
44 | position: absolute;
45 | width: 6px;
46 | color: var( --gsui-col-pattern8 );
47 | background-color: currentColor;
48 | }
49 | .gsuiSliderGroup-sliderSelected .gsuiSliderGroup-sliderInner {
50 | color: var( --gsui-col-patternSelected8 );
51 | }
52 | .gsuiSliderGroup-sliderInner::after {
53 | content: "";
54 | position: absolute;
55 | box-sizing: border-box;
56 | width: 1000000px;
57 | height: 100%;
58 | border: 0 solid;
59 | border-width: 1px 0 0;
60 | }
61 | .gsuiSliderGroup-sliderInnerDown::after {
62 | border-width: 0 0 1px;
63 | }
64 |
65 | /* .......................................................................... */
66 | .gsuiSliderGroup-loop,
67 | .gsuiSliderGroup-currentTime {
68 | position: absolute;
69 | z-index: 2147483647;
70 | top: 0;
71 | bottom: 0;
72 | pointer-events: none;
73 | }
74 | .gsuiSliderGroup-defaultValue {
75 | position: absolute;
76 | left: 0;
77 | right: 0;
78 | border-top: 1px dotted #0008;
79 | pointer-events: none;
80 | }
81 | .gsuiSliderGroup-currentTime {
82 | width: 2px;
83 | margin-left: -1px;
84 | background-color: var( --gsui-col-currentTimeCursor );
85 | }
86 | gsui-slidergroup[ currenttime="0" ] .gsuiSliderGroup-currentTime {
87 | display: none;
88 | }
89 | .gsuiSliderGroup-loop {
90 | background-color: transparent;
91 | transition: .2s background-color;
92 | }
93 | .gsuiSliderGroup-loopA { left: 0; }
94 | .gsuiSliderGroup-loopB { right: 0; }
95 | .gsuiSliderGroup-loopOn {
96 | background-color: #0004;
97 | }
98 |
--------------------------------------------------------------------------------
/gsuiSliderGroup/gsuiSliderGroup.html.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | GSUsetTemplate( "gsui-slidergroup", () =>
4 | GSUcreateDiv( { class: "gsuiSliderGroup-slidersWrap" },
5 | GSUcreateDiv( { class: "gsuiSliderGroup-sliders" },
6 | GSUcreateElement( "gsui-beatlines", { coloredbeats: "" } ),
7 | GSUcreateDiv( { class: "gsuiSliderGroup-currentTime" } ),
8 | GSUcreateDiv( { class: "gsuiSliderGroup-defaultValue" } ),
9 | GSUcreateDiv( { class: "gsuiSliderGroup-loop gsuiSliderGroup-loopA" } ),
10 | GSUcreateDiv( { class: "gsuiSliderGroup-loop gsuiSliderGroup-loopB" } ),
11 | ),
12 | )
13 | );
14 |
15 | GSUsetTemplate( "gsui-slidergroup-slider", () =>
16 | GSUcreateDiv( { class: "gsuiSliderGroup-slider" },
17 | GSUcreateDiv( { class: "gsuiSliderGroup-sliderInner" } ),
18 | )
19 | );
20 |
--------------------------------------------------------------------------------
/gsuiSliderGroup/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
74 |
75 |
76 |
--------------------------------------------------------------------------------
/gsuiStepSelect/gsuiStepSelect.css:
--------------------------------------------------------------------------------
1 | gsui-step-select {
2 | display: inline-flex;
3 | align-items: center;
4 | justify-content: end;
5 | gap: 6px;
6 | height: 20px;
7 | padding: 0 6px;
8 | border-radius: 4px;
9 | font-size: 14px;
10 | cursor: pointer;
11 | background-color: #0005;
12 | background-color: #fff3;
13 | opacity: .8;
14 | }
15 | gsui-step-select:hover {
16 | opacity: 1;
17 | }
18 |
19 | .gsuiStepSelect-frac {
20 | font-family: var( --gsui-font-number );
21 | }
22 |
23 | gsui-step-select .gsuiIcon {
24 | line-height: 20px;
25 | opacity: .5;
26 | }
27 | gsui-step-select:hover .gsuiIcon {
28 | opacity: .6;
29 | }
30 |
--------------------------------------------------------------------------------
/gsuiStepSelect/gsuiStepSelect.html.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | GSUsetTemplate( "gsui-step-select", () => [
4 | GSUcreateSpan( { class: "gsuiStepSelect-frac", inert: true } ),
5 | GSUcreateIcon( { icon: "magnet" } ),
6 | ] );
7 |
--------------------------------------------------------------------------------
/gsuiStepSelect/gsuiStepSelect.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | class gsuiStepSelect extends gsui0ne {
4 | #step = 1;
5 |
6 | constructor() {
7 | super( {
8 | $cmpName: "gsuiStepSelect",
9 | $tagName: "gsui-step-select",
10 | $elements: {
11 | $frac: ".gsuiStepSelect-frac",
12 | },
13 | $attributes: {
14 | step: 1,
15 | title: "Grid snap",
16 | },
17 | } );
18 | Object.seal( this );
19 | this.onclick = this.#onclick.bind( this );
20 | }
21 |
22 | // .........................................................................
23 | static get observedAttributes() {
24 | return [ "step" ];
25 | }
26 | $attributeChanged( prop, val ) {
27 | if ( prop === "step" ) {
28 | this.#step = +val;
29 | this.$elements.$frac.textContent = gsuiStepSelect.#stepToFraction( this.#step );
30 | }
31 | }
32 |
33 | // .........................................................................
34 | $getStep() {
35 | return this.#step;
36 | }
37 |
38 | // .........................................................................
39 | #onclick() {
40 | const step = gsuiStepSelect.#nextStep( this.#step );
41 |
42 | GSUsetAttribute( this, "step", step );
43 | this.$dispatch( "onchange", step );
44 | }
45 | static #nextStep( v ) {
46 | return (
47 | v >= 1 ? .5 :
48 | v >= .5 ? .25 :
49 | v >= .25 ? .125 : 1
50 | );
51 | }
52 | static #stepToFraction( v ) {
53 | return (
54 | v >= 1 ? "1" :
55 | v >= .5 ? "1/2" :
56 | v >= .25 ? "1/4" : "1/8"
57 | );
58 | }
59 | }
60 |
61 | GSUdefineElement( "gsui-step-select", gsuiStepSelect );
62 |
--------------------------------------------------------------------------------
/gsuiStepSelect/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/gsuiSynthesizer/gsuiSynthesizer.html.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | GSUsetTemplate( "gsui-synthesizer", () => [
4 | GSUcreateDiv( { class: "gsuiSynthesizer-shadowTop" } ),
5 | GSUcreateDiv( { class: "gsuiSynthesizer-scrollArea" },
6 | // .....................................................................
7 | GSUcreateDiv( { class: "gsuiSynthesizer-head" },
8 | GSUgetTemplate( "gsui-synthesizer-headTitle", { name: "envelopes", help: "synth-envelopes" } ),
9 | GSUgetTemplate( "gsui-synthesizer-headTab", { id: "env gain", name: "gain" } ),
10 | GSUgetTemplate( "gsui-synthesizer-headTab", { id: "env detune", name: "pitch" } ),
11 | GSUgetTemplate( "gsui-synthesizer-headTab", { id: "env lowpass", name: "lowpass" } ),
12 | ),
13 | GSUcreateElement( "gsui-envelope" ),
14 | // .....................................................................
15 | GSUcreateDiv( { class: "gsuiSynthesizer-head" },
16 | GSUgetTemplate( "gsui-synthesizer-headTitle", { name: "LFOs", help: "synth-LFOs" } ),
17 | GSUgetTemplate( "gsui-synthesizer-headTab", { id: "lfo gain", name: "gain" } ),
18 | GSUgetTemplate( "gsui-synthesizer-headTab", { id: "lfo detune", name: "pitch" } ),
19 | ),
20 | GSUcreateElement( "gsui-lfo" ),
21 | // .....................................................................
22 | GSUcreateDiv( { class: "gsuiSynthesizer-head gsuiSynthesizer-headNoise" },
23 | GSUgetTemplate( "gsui-synthesizer-headTitle", { name: "noise", help: "synth-noise" } ),
24 | GSUcreateElement( "gsui-toggle", { off: true } ),
25 | ),
26 | GSUcreateElement( "gsui-noise" ),
27 | // .....................................................................
28 | GSUcreateDiv( { class: "gsuiSynthesizer-head gsuiSynthesizer-headOscs" },
29 | GSUgetTemplate( "gsui-synthesizer-headTitle", { name: "oscillators", help: "synth-oscillator" } ),
30 | ),
31 | GSUcreateDiv( { class: "gsuiSynthesizer-oscList" },
32 | GSUcreateButton( { class: "gsuiSynthesizer-newOsc" },
33 | GSUcreateIcon( { icon: "plus" } ),
34 | ),
35 | ),
36 | ),
37 | GSUcreateDiv( { class: "gsuiSynthesizer-shadowBottom" } ),
38 | ] );
39 |
40 | GSUsetTemplate( "gsui-synthesizer-headTitle", p =>
41 | GSUcreateSpan( { class: "gsuiSynthesizer-headTitle" },
42 | GSUcreateSpan( null, p.name ),
43 | GSUcreateElement( "gsui-help-link", { page: p.help } ),
44 | )
45 | );
46 |
47 | GSUsetTemplate( "gsui-synthesizer-headTab", p =>
48 | GSUcreateDiv( { class: "gsuiSynthesizer-headTab", "data-tab": p.id },
49 | GSUcreateElement( "gsui-toggle", { off: true } ),
50 | GSUcreateSpan( { inert: true }, p.name ),
51 | )
52 | );
53 |
--------------------------------------------------------------------------------
/gsuiTempo/gsuiTempo.html.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | GSUsetTemplate( "gsui-tempo", () =>
4 | GSUcreateButton( { class: "gsuiTempo-btn", title: "Edit the time signature and BPM" },
5 | GSUcreateDiv( { class: "gsuiTempo-timeDivision" },
6 | GSUcreateSpan( { class: "gsuiTempo-beatsPerMeasure" } ),
7 | GSUcreateSpan( { class: "gsuiTempo-stepsPerBeat" } ),
8 | ),
9 | GSUcreateSpan( { class: "gsuiTempo-bpm" } ),
10 | ),
11 | );
12 |
13 | GSUsetTemplate( "gsui-tempo-dropdown", () =>
14 | GSUcreateElement( "form", { class: "gsuiTempo-popup", tabindex: -1 },
15 | GSUcreateDiv( { class: "gsuiTempo-row" },
16 | GSUcreateLabel( null, "Beats per measure" ),
17 | GSUcreateInput( { type: "number", min: 1, max: 16, required: true } ),
18 | ),
19 | GSUcreateDiv( { class: "gsuiTempo-row" },
20 | GSUcreateLabel( null, "Steps per beat" ),
21 | GSUcreateInput( { type: "number", min: 1, max: 16, required: true } ),
22 | ),
23 | GSUcreateDiv( { class: "gsuiTempo-row gsuiTempo-row-bpm" },
24 | GSUcreateLabel( null, "BPM " ),
25 | GSUcreateDiv( null,
26 | GSUcreateInput( { type: "number", step: .01, min: 1, max: 999.99, required: true } ),
27 | GSUcreateButton( { class: "gsuiTempo-tap", icon: "tint" } ),
28 | ),
29 | ),
30 | GSUcreateDiv( { class: "gsuiTempo-row" },
31 | GSUcreateButton( { type: "submit" }, "Ok" ),
32 | ),
33 | ),
34 | );
35 |
--------------------------------------------------------------------------------
/gsuiTempo/gsuiTempo.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | class gsuiTempo extends gsui0ne {
4 | #dropdown = new gsuiDropdown();
5 | #popup = GSUfindElements( GSUgetTemplate( "gsui-tempo-dropdown" ), {
6 | $form: ".gsuiTempo-popup",
7 | $bpmTap: ".gsuiTempo-tap",
8 | } );
9 |
10 | constructor() {
11 | super( {
12 | $cmpName: "gsuiTempo",
13 | $tagName: "gsui-tempo",
14 | $elements: {
15 | $btn: ".gsuiTempo-btn",
16 | $bpm: ".gsuiTempo-bpm",
17 | $timediv: ".gsuiTempo-timeDivision",
18 | },
19 | $attributes: {
20 | timedivision: "4/4",
21 | bpm: 60,
22 | },
23 | } );
24 | Object.seal( this );
25 | this.#dropdown.$setDirection( "bottom" );
26 | this.#dropdown.$bindTargetElement( this.$elements.$btn );
27 | this.#dropdown.$onopenCreateElement( this.#createPopup.bind( this ) );
28 | this.#popup.$form.onsubmit = this.$onsubmitPopup.bind( this );
29 | this.#popup.$form.onkeydown = e => e.stopPropagation();
30 | this.#popup.$bpmTap.onclick = () => this.#popup.$form[ 2 ].value = gswaBPMTap.$tap();
31 | }
32 |
33 | // .........................................................................
34 | static get observedAttributes() {
35 | return [ "bpm", "timedivision" ];
36 | }
37 | $attributeChanged( prop, val ) {
38 | switch ( prop ) {
39 | case "bpm":
40 | this.#popup.$form[ 2 ].value =
41 | this.$elements.$bpm.textContent = val;
42 | break;
43 | case "timedivision": {
44 | const div = GSUsplitNums( val, "/" );
45 |
46 | this.#popup.$form[ 0 ].value = this.$elements.$timediv.firstChild.textContent = div[ 0 ];
47 | this.#popup.$form[ 1 ].value = this.$elements.$timediv.lastChild.textContent = div[ 1 ];
48 | } break;
49 | }
50 | }
51 |
52 | // .........................................................................
53 | #createPopup() {
54 | const f = this.#popup.$form;
55 | const time = GSUsplitNums( GSUgetAttribute( this, "timedivision" ), "/" );
56 |
57 | f[ 0 ].value = time[ 0 ];
58 | f[ 1 ].value = time[ 1 ];
59 | f[ 2 ].value = GSUgetAttributeNum( this, "bpm" );
60 | return f;
61 | }
62 | $onsubmitPopup( e ) {
63 | const f = e.target;
64 | const time = `${ f[ 0 ].value }/${ f[ 1 ].value }`;
65 | const bpm = f[ 2 ].value;
66 |
67 | if ( time !== GSUgetAttribute( this, "timedivision" ) || bpm !== GSUgetAttribute( this, "bpm" ) ) {
68 | this.$dispatch( "change", {
69 | bpm: +bpm,
70 | timedivision: time,
71 | } );
72 | }
73 | this.#dropdown.$close();
74 | return false;
75 | }
76 | }
77 |
78 | GSUdefineElement( "gsui-tempo", gsuiTempo );
79 |
--------------------------------------------------------------------------------
/gsuiTempo/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/gsuiTimeline/gsuiTimeline.html.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | GSUsetTemplate( "gsui-timeline", () => [
4 | GSUcreateDiv( { class: "gsuiTimeline-steps" } ),
5 | GSUcreateDiv( { class: "gsuiTimeline-beats" } ),
6 | GSUcreateDiv( { class: "gsuiTimeline-measures" } ),
7 | GSUcreateDiv( { class: "gsuiTimeline-loop" },
8 | GSUcreateDiv( { class: "gsuiTimeline-loopBody" } ),
9 | GSUcreateDiv( { class: "gsuiTimeline-loopHandle gsuiTimeline-loopHandleA" } ),
10 | GSUcreateDiv( { class: "gsuiTimeline-loopBorder gsuiTimeline-loopBorderA" } ),
11 | GSUcreateDiv( { class: "gsuiTimeline-loopHandle gsuiTimeline-loopHandleB" } ),
12 | GSUcreateDiv( { class: "gsuiTimeline-loopBorder gsuiTimeline-loopBorderB" } ),
13 | ),
14 | GSUcreateElementSVG( "svg", { class: "gsuiTimeline-cursor", width: "16", height: "10" },
15 | GSUcreateElementSVG( "polygon", { points: "2,2 8,8 14,2" } ),
16 | ),
17 | GSUcreateElementSVG( "svg", { class: "gsuiTimeline-cursorPreview", width: "16", height: "10" },
18 | GSUcreateElementSVG( "polygon", { points: "2,2 8,8 14,2" } ),
19 | ),
20 | ] );
21 |
--------------------------------------------------------------------------------
/gsuiTimewindow/gsuiTimewindow.html.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | GSUsetTemplate( "gsui-timewindow", () => [
4 | GSUcreateDiv( { class: "gsuiTimewindow-scrollArea" },
5 | GSUcreateDiv( { class: "gsuiTimewindow-panel" },
6 | GSUcreateDiv( { class: "gsuiTimewindow-panelUp" },
7 | GSUcreateElement( "gsui-step-select" ),
8 | GSUcreateElement( "gsui-slider", { "data-zoom": "y", type: "linear-y", "mousemove-size": 400, min: 0, max: 1, step: .01, title: "zooming Y" } ),
9 | GSUcreateElement( "gsui-slider", { "data-zoom": "x", type: "linear-y", "mousemove-size": 400, min: 0, max: 1, step: .01, title: "zooming X" } ),
10 | ),
11 | GSUcreateDiv( { class: "gsuiTimewindow-panelContent" } ),
12 | GSUcreateDiv( { class: "gsuiTimewindow-panelContentDown" },
13 | GSUcreateDiv( { class: "gsuiTimewindow-panelExtend gsuiTimewindow-panelExtendX" } ),
14 | ),
15 | GSUcreateDiv( { class: "gsuiTimewindow-panelExtend gsuiTimewindow-panelExtendY" } ),
16 | ),
17 | GSUcreateDiv( { class: "gsuiTimewindow-main" },
18 | GSUcreateDiv( { class: "gsuiTimewindow-time" },
19 | GSUcreateElement( "gsui-timeline" ),
20 | ),
21 | GSUcreateDiv( { class: "gsuiTimewindow-mainBody" },
22 | GSUcreateDiv( { class: "gsuiTimewindow-mainContent" },
23 | GSUcreateElement( "gsui-beatlines", { coloredbeats: "" } ),
24 | GSUcreateDiv( { class: "gsuiTimewindow-currentTime" } ),
25 | GSUcreateDiv( { class: "gsuiTimewindow-loop gsuiTimewindow-loopA" } ),
26 | GSUcreateDiv( { class: "gsuiTimewindow-loop gsuiTimewindow-loopB" } ),
27 | GSUcreateDiv( { class: "gsuiTimewindow-rows" } ),
28 | ),
29 | ),
30 | GSUcreateDiv( { class: "gsuiTimewindow-contentDown" },
31 | GSUcreateDiv( { class: "gsuiTimewindow-panelExtend gsuiTimewindow-panelExtendX" } ),
32 | ),
33 | ),
34 | ),
35 | GSUcreateDiv( { class: "gsuiTimewindow-minimap" },
36 | GSUcreateDiv( { class: "gsuiTimewindow-minimapPanel" } ),
37 | GSUcreateDiv( { class: "gsuiTimewindow-minimapTrack", "data-action": "track" },
38 | GSUcreateDiv( { class: "gsuiTimewindow-minimapLoop", inert: true } ),
39 | GSUcreateDiv( { class: "gsuiTimewindow-minimapCurrentTime", inert: true } ),
40 | GSUcreateDiv( { class: "gsuiTimewindow-minimapThumb", "data-action": "thumb" },
41 | GSUcreateDiv( { class: "gsuiTimewindow-minimapThumb-crop", "data-action": "cropA" } ),
42 | GSUcreateDiv( { class: "gsuiTimewindow-minimapThumb-crop", "data-action": "cropB" } ),
43 | ),
44 | ),
45 | ),
46 | ] );
47 |
48 |
--------------------------------------------------------------------------------
/gsuiTitleUser/gsuiTitleUser.html.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | GSUsetTemplate( "gsui-titleuser", () => [
4 | GSUcreateDiv( { class: "gsuiTitleUser-top" },
5 | GSUcreateSpan( { class: "gsuiTitleUser-gs", inert: true }, "GridSound" ),
6 | GSUcreateButton( { class: "gsuiTitleUser-login", icon: "profile", title: "Login / connection" } ),
7 | GSUcreateAExt( { class: "gsuiTitleUser-user", title: "Go to your profile" },
8 | GSUcreateDiv( { class: "gsuiTitleUser-avatar", inert: true } ),
9 | GSUcreateDiv( { class: "gsuiTitleUser-names", inert: true },
10 | GSUcreateSpan( { class: "gsuiTitleUser-name" } ),
11 | GSUcreateSpan( { class: "gsuiTitleUser-username" } ),
12 | ),
13 | ),
14 | GSUcreateButton( { class: "gsuiTitleUser-logout", icon: "logout", title: "Logout / disconnect" } ),
15 | ),
16 | GSUcreateDiv( { class: "gsuiTitleUser-cmp" },
17 | GSUcreateButton( { class: "gsuiTitleUser-save", icon: "upload", title: "Save composition" } ),
18 | GSUcreateSpan( { class: "gsuiTitleUser-justSaved", inert: true }, "SAVED" ),
19 | GSUcreateButton( { class: "gsuiTitleUser-rename", title: "Edit composition's title" },
20 | GSUcreateSpan( { class: "gsuiTitleUser-cmpName", inert: true } ),
21 | GSUcreateIcon( { class: "gsuiTitleUser-cmpEditIcon", icon: "pen" } ),
22 | GSUcreateSpan( { class: "gsuiTitleUser-cmpDur", inert: true } ),
23 | ),
24 | GSUcreateInput( { class: "gsuiTitleUser-rename-inp", type: "text", placeholder: "Untitled..." } ),
25 | ),
26 | ] );
27 |
28 | GSUsetTemplate( "gsui-titleuser-popup", () =>
29 | GSUcreateDiv( { class: "gsuiTitleUser-popup" },
30 | GSUcreateElement( "fieldset", null,
31 | GSUcreateElement( "legend", null, "Sign in" ),
32 | GSUcreateDiv( { class: "gsuiPopup-row" },
33 | GSUcreateDiv( { class: "gsuiPopup-row-title" },
34 | GSUcreateSpan( null, "Username" ),
35 | GSUcreateElement( "br" ),
36 | GSUcreateElement( "small", null, "(or email)" ),
37 | ),
38 | GSUcreateDiv( { class: "gsuiPopup-row-values" },
39 | GSUcreateInput( { class: "gsuiPopup-inputText", required: true, name: "email", type: "text" } ),
40 | ),
41 | ),
42 | GSUcreateDiv( { class: "gsuiPopup-row" },
43 | GSUcreateDiv( { class: "gsuiPopup-row-title" }, "Password" ),
44 | GSUcreateDiv( { class: "gsuiPopup-row-values" },
45 | GSUcreateInput( { class: "gsuiPopup-inputText", required: true, name: "password", type: "password" } ),
46 | ),
47 | ),
48 | GSUcreateDiv( { class: "gsuiTitleUser-popup-error" } ),
49 | ),
50 | GSUcreateAExt( { href: "https://gridsound.com/#/forgotPassword" }, "Forgot password ?" ),
51 | GSUcreateElement( "br" ),
52 | GSUcreateAExt( { href: "https://gridsound.com/#/auth" }, "Create a new account" ),
53 | )
54 | );
55 |
--------------------------------------------------------------------------------
/gsuiToggle/gsuiToggle.css:
--------------------------------------------------------------------------------
1 | gsui-toggle {
2 | position: relative;
3 | display: inline-flex;
4 | align-items: center;
5 | justify-content: center;
6 | font-size: 8px;
7 | outline: 0;
8 | cursor: pointer;
9 | color: var( --gsui-toggle-on );
10 | transition: color .25s;
11 | }
12 | gsui-toggle[ off ] {
13 | color: var( --gsui-toggle-off );
14 | }
15 |
--------------------------------------------------------------------------------
/gsuiToggle/gsuiToggle.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | class gsuiToggle extends gsui0ne {
4 | constructor() {
5 | super( {
6 | $cmpName: "gsuiToggle",
7 | $tagName: "gsui-toggle",
8 | $template: GSUcreateIcon( { icon: "hexagon" } ),
9 | $attributes: { tabindex: 0 },
10 | } );
11 | Object.seal( this );
12 | this.oncontextmenu = GSUnoopFalse;
13 | this.onmousedown = e => {
14 | if ( e.button === 2 ) {
15 | this.$dispatch( "toggleSolo" );
16 | } else if ( e.button === 0 ) {
17 | const off = GSUhasAttribute( this, "off" );
18 |
19 | GSUsetAttribute( this, "off", !off );
20 | this.$dispatch( "toggle", off );
21 | }
22 | };
23 | }
24 | $isOn() {
25 | return !GSUhasAttribute( this, "off" );
26 | }
27 | }
28 |
29 | GSUdefineElement( "gsui-toggle", gsuiToggle );
30 |
--------------------------------------------------------------------------------
/gsuiToggle/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/gsuiTrack/gsuiTrack.css:
--------------------------------------------------------------------------------
1 | gsui-track {
2 | box-sizing: border-box;
3 | display: flex;
4 | height: 100%;
5 | border-top: var( --gsui-item-brdtop );
6 | border-bottom: var( --gsui-item-brdbottom );
7 | background-color: var( --gsui-item-bg );
8 | }
9 | gsui-track,
10 | .gsuiTrack-row {
11 | transition: .2s background-color;
12 | }
13 | gsui-track[ mute ] {
14 | border: 0;
15 | background-color: var( --gsui-item-bg-disabled );
16 | }
17 |
18 | /* .......................................................................... */
19 | .gsuiTrack-row {
20 | position: relative;
21 | z-index: 0;
22 | height: var( --gsuiTimewindow-lineH );
23 | }
24 | .gsuiTrack-row::before {
25 | content: "";
26 | position: absolute;
27 | inset: 0;
28 | border-top: 2px solid #ffffff0b;
29 | border-bottom: 2px solid #00000026;
30 | }
31 | .gsuiTrack-row.gsui-mute {
32 | border: 0;
33 | background-color: #00000012;
34 | }
35 | .gsuiTrack-row > div {
36 | position: absolute;
37 | inset: 0;
38 | font-size: var( --gsuiTimewindow-pxperbeat );
39 | }
40 | .gsuiTrack-row.gsui-mute > div {
41 | top: 0;
42 | }
43 |
44 | /* .......................................................................... */
45 | gsui-track gsui-toggle {
46 | min-width: 24px;
47 | }
48 | .gsuiTrack-nameWrap {
49 | position: relative;
50 | flex: 1;
51 | }
52 | .gsuiTrack-name {
53 | box-sizing: border-box;
54 | position: absolute;
55 | inset: 0;
56 | width: 100%;
57 | border: 0;
58 | outline: 0;
59 | padding-right: 10px;
60 | font-size: 12px;
61 | font-weight: bold;
62 | font-family: inherit;
63 | text-overflow: ellipsis;
64 | color: inherit;
65 | cursor: default;
66 | background: none;
67 | }
68 | .gsuiTrack-name[ disabled ] {
69 | pointer-events: none;
70 | }
71 | gsui-track[ mute ] .gsuiTrack-name {
72 | opacity: .5;
73 | }
74 | .gsuiTrack-name:focus {
75 | font-weight: normal;
76 | }
77 | .gsuiTrack-name::placeholder {
78 | color: inherit;
79 | font-style: italic;
80 | font-weight: normal;
81 | }
82 | .gsuiTrack-name:focus::placeholder {
83 | color: transparent;
84 | }
85 |
--------------------------------------------------------------------------------
/gsuiTrack/gsuiTrack.html.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | GSUsetTemplate( "gsui-track", () => [
4 | GSUcreateElement( "gsui-toggle", { title: "toggle track (right click for solo)" } ),
5 | GSUcreateDiv( { class: "gsuiTrack-nameWrap" },
6 | GSUcreateInput( { class: "gsuiTrack-name", type: "text", disabled: true, spellcheck: "false" } ),
7 | ),
8 | ] );
9 |
10 | GSUsetTemplate( "gsui-track-row", () =>
11 | GSUcreateDiv( { class: "gsuiTrack-row gsui-row" },
12 | GSUcreateDiv(),
13 | )
14 | );
15 |
--------------------------------------------------------------------------------
/gsuiTrack/gsuiTrack.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | class gsuiTrack extends gsui0ne {
4 | rowElement = GSUgetTemplate( "gsui-track-row" );
5 |
6 | constructor() {
7 | super( {
8 | $cmpName: "gsuiTrack",
9 | $tagName: "gsui-track",
10 | $elements: {
11 | $inpName: ".gsuiTrack-name",
12 | },
13 | $attributes: {
14 | name: "",
15 | order: 0,
16 | },
17 | } );
18 | Object.seal( this );
19 | this.onchange = this.#onchange.bind( this );
20 | this.onkeydown = this.#onkeydown.bind( this );
21 | this.ondblclick = this.#ondblclick.bind( this );
22 | this.$elements.$inpName.onblur = this.#onblur.bind( this );
23 | GSUlistenEvents( this, {
24 | gsuiToggle: {
25 | toggle: d => {
26 | GSUsetAttribute( this, "mute", !d.args[ 0 ] );
27 | this.$dispatch( "toggle", d.args[ 0 ] );
28 | },
29 | toggleSolo: () => {
30 | GSUsetAttribute( this, "mute", false );
31 | this.$dispatch( "toggleSolo" );
32 | },
33 | },
34 | } );
35 | }
36 |
37 | // .........................................................................
38 | static get observedAttributes() {
39 | return [ "mute", "name", "order" ];
40 | }
41 | $attributeChanged( prop, val ) {
42 | switch ( prop ) {
43 | case "mute":
44 | this.rowElement.classList.toggle( "gsui-mute", val !== null );
45 | GSUsetAttribute( this.firstElementChild, "off", val !== null );
46 | break;
47 | case "name":
48 | this.$elements.$inpName.value = val;
49 | break;
50 | case "order":
51 | this.$elements.$inpName.placeholder = `track ${ +val + 1 }`;
52 | break;
53 | }
54 | }
55 |
56 | // .........................................................................
57 | #ondblclick( e ) {
58 | if ( e.target.classList.contains( "gsuiTrack-nameWrap" ) ) {
59 | this.$elements.$inpName.disabled = false;
60 | this.$elements.$inpName.select();
61 | this.$elements.$inpName.focus();
62 | }
63 | }
64 | #onkeydown( e ) {
65 | if ( e.target === this.$elements.$inpName ) {
66 | e.stopPropagation();
67 | switch ( e.key ) {
68 | case "Escape": this.$elements.$inpName.value = GSUgetAttribute( this, "name" );
69 | case "Enter": this.$elements.$inpName.blur();
70 | }
71 | }
72 | }
73 | #onchange() {
74 | const n = this.$elements.$inpName.value.trim();
75 |
76 | this.$elements.$inpName.disabled = true;
77 | GSUsetAttribute( this, "name", n );
78 | this.$dispatch( "rename", n );
79 | }
80 | #onblur() {
81 | this.$elements.$inpName.disabled = true;
82 | }
83 | }
84 |
85 | GSUdefineElement( "gsui-track", gsuiTrack );
86 |
--------------------------------------------------------------------------------
/gsuiTrack/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/gsuiTracklist/gsuiTracklist.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | class gsuiTracklist extends gsui0ne {
4 | #tracks = new Map();
5 |
6 | constructor() {
7 | super( {
8 | $cmpName: "gsuiTracklist",
9 | $tagName: "gsui-tracklist",
10 | } );
11 | Object.seal( this );
12 | GSUlistenEvents( this, {
13 | gsuiTrack: {
14 | rename: ( d, tr ) => this.$dispatch( "renameTrack", tr.dataset.id, d.args[ 0 ] ),
15 | toggle: ( d, tr ) => this.$dispatch( "toggleTrack", tr.dataset.id ),
16 | toggleSolo: ( d, tr ) => this.$dispatch( "toggleSoloTrack", tr.dataset.id ),
17 | },
18 | } );
19 | }
20 |
21 | // .........................................................................
22 | $getTrack( id ) {
23 | return this.#tracks.get( id );
24 | }
25 | $addTrack( id ) {
26 | const tr = GSUcreateElement( "gsui-track", { "data-id": id } );
27 |
28 | tr.rowElement.dataset.id = id;
29 | this.#tracks.set( id, tr );
30 | this.append( tr );
31 | return tr;
32 | }
33 | $removeTrack( id ) {
34 | const tr = this.#tracks.get( id );
35 |
36 | tr.remove();
37 | tr.rowElement.remove();
38 | this.#tracks.delete( id );
39 | }
40 | }
41 |
42 | GSUdefineElement( "gsui-tracklist", gsuiTracklist );
43 |
--------------------------------------------------------------------------------
/gsuiWavetableGraph/gsuiWavetableGraph.css:
--------------------------------------------------------------------------------
1 | gsui-wavetable-graph {
2 | --gsuiWavetableGraph-waves-selected: #8f8;
3 | --gsuiWavetableGraph-waves: #a0a9ff;
4 | --gsuiWavetableGraph-morph: #fff;
5 | position: relative;
6 | display: block;
7 | color: var( --gsuiWavetableGraph-waves );
8 | cursor: grab;
9 | touch-action: none;
10 | }
11 | gsui-wavetable-graph svg {
12 | position: absolute;
13 | inset: 0;
14 | stroke: currentColor;
15 | }
16 |
17 | /* .......................................................................... */
18 | .gsuiWavetableGraph-box line {
19 | stroke-width: 2px;
20 | opacity: .1;
21 | }
22 |
23 | /* .......................................................................... */
24 | .gsuiWavetableGraph-morph polyline:nth-child( even ) {
25 | fill: none;
26 | stroke-width: 3px;
27 | stroke: var( --gsuiWavetableGraph-morph );
28 | }
29 | .gsuiWavetableGraph-morph polyline:nth-child( odd ) {
30 | stroke: none;
31 | fill: var( --gsuiWavetableGraph-morph );
32 | fill-opacity: .4;
33 | }
34 |
35 | /* .......................................................................... */
36 | gsui-wavetable-graph:has( .gsuiWavetableGraph-morph polyline[ points ] ) .gsuiWavetableGraph-waves {
37 | opacity: .5;
38 | }
39 | .gsuiWavetableGraph-waves polyline:nth-child( even ) {
40 | fill: none;
41 | stroke-width: 2px;
42 | stroke: currentColor;
43 | }
44 | .gsuiWavetableGraph-waves polyline:nth-child( odd ) {
45 | stroke: none;
46 | fill: currentColor;
47 | fill-opacity: .2;
48 | }
49 | .gsuiWavetableGraph-waves polyline:nth-child( even )[ data-selected ] {
50 | color: var( --gsuiWavetableGraph-waves-selected );
51 | }
52 | .gsuiWavetableGraph-waves polyline:nth-child( odd )[ data-selected ] {
53 | color: var( --gsuiWavetableGraph-waves-selected );
54 | }
55 |
56 | /* .......................................................................... */
57 | .gsuiWavetableGraph-interp polyline {
58 | fill: none;
59 | stroke: currentColor;
60 | stroke-width: 1px;
61 | opacity: .2;
62 | }
63 |
--------------------------------------------------------------------------------
/gsuiWindows/gsuiWindow.html.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | GSUsetTemplate( "gsui-window", id => [
4 | GSUcreateDiv( { class: "gsuiWindow-handlers" },
5 | GSUcreateDiv( { class: "gsuiWindow-handler", "data-dir": "n" } ),
6 | GSUcreateDiv( { class: "gsuiWindow-handler", "data-dir": "e" } ),
7 | GSUcreateDiv( { class: "gsuiWindow-handler", "data-dir": "s" } ),
8 | GSUcreateDiv( { class: "gsuiWindow-handler", "data-dir": "w" } ),
9 | GSUcreateDiv( { class: "gsuiWindow-handler", "data-dir": "nw" } ),
10 | GSUcreateDiv( { class: "gsuiWindow-handler", "data-dir": "ne" } ),
11 | GSUcreateDiv( { class: "gsuiWindow-handler", "data-dir": "sw" } ),
12 | GSUcreateDiv( { class: "gsuiWindow-handler", "data-dir": "se" } ),
13 | ),
14 | GSUcreateDiv( { class: "gsuiWindow-wrap" },
15 | GSUcreateDiv( { class: "gsuiWindow-head" },
16 | GSUcreateButton( { class: "gsuiWindow-icon gsuiIcon", tabindex: -1 } ),
17 | GSUcreateDiv( { class: "gsuiWindow-name", inert: true } ),
18 | GSUcreateDiv( { class: "gsuiWindow-headContent" } ),
19 | GSUcreateDiv( { class: "gsuiWindow-headBtns" },
20 | GSUcreateButton( { class: "gsuiWindow-headBtn", "data-action": "minimize", icon: "minimize", title: "Minimize" } ),
21 | GSUcreateButton( { class: "gsuiWindow-headBtn", "data-action": "restore", title: "Restore" },
22 | GSUcreateIcon( { icon: "restore" } ),
23 | GSUcreateIcon( { icon: "compress" } ),
24 | ),
25 | GSUcreateButton( { class: "gsuiWindow-headBtn", "data-action": "maximize", title: "Maximize" },
26 | GSUcreateIcon( { icon: "maximize" } ),
27 | GSUcreateIcon( { icon: "expand" } ),
28 | ),
29 | GSUcreateButton( { class: "gsuiWindow-headBtn", "data-action": "close", icon: "close", title: "Close" } ),
30 | ),
31 | ),
32 | GSUcreateDiv( { class: "gsuiWindow-content" } ),
33 | ),
34 | ] );
35 |
--------------------------------------------------------------------------------
/gsuiWindows/gsuiWindows.css:
--------------------------------------------------------------------------------
1 | gsui-windows {
2 | display: block;
3 | width: 100%;
4 | height: 100%;
5 | position: relative;
6 | overflow: hidden;
7 | scroll-behavior: smooth;
8 | }
9 |
--------------------------------------------------------------------------------
/gsuiWindows/gsuiWindows.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | class gsuiWindows extends gsui0ne {
4 | #elWindows = {};
5 | #focusedWindow = null;
6 |
7 | constructor() {
8 | super( {
9 | $cmpName: "gsuiWindows",
10 | $tagName: "gsui-windows",
11 | } );
12 | Object.seal( this );
13 | GSUlistenEvents( this, {
14 | gsuiWindow: {
15 | open: ( d, win ) => this.#onopen( win ),
16 | close: ( d, win ) => this.#onclose( win ),
17 | startMousemoving: d => this.#startMousemoving( ...d.args ),
18 | },
19 | } );
20 | this.onpointerleave = e => this.onpointerup?.( e );
21 | }
22 |
23 | // .........................................................................
24 | $createWindow( id ) {
25 | const win = GSUcreateElement( "gsui-window", { "data-id": id } );
26 |
27 | win.addEventListener( "focusin", this.#onfocusinWin.bind( this, win ) );
28 | this.#elWindows[ id ] = win;
29 | this.append( win );
30 | return win;
31 | }
32 | $window( winId ) {
33 | return this.#elWindows[ winId ];
34 | }
35 |
36 | // .........................................................................
37 | #startMousemoving( cursor, ptrId, fnMove, fnUp ) {
38 | GSUunselectText();
39 | this.setPointerCapture( ptrId );
40 | this.onpointerup = this.#stopMousemoving.bind( this, fnUp );
41 | this.onpointermove = fnMove;
42 | this.style.cursor = cursor;
43 | }
44 | #stopMousemoving( fnUp, e ) {
45 | this.releasePointerCapture( e.pointerId );
46 | this.onpointerup =
47 | this.onpointermove = null;
48 | this.style.cursor = "";
49 | fnUp( e );
50 | }
51 | #onopen( win ) {
52 | this.#onfocusinWin( win );
53 | this.$dispatch( "open", win );
54 | }
55 | #onclose( win ) {
56 | if ( win === this.#focusedWindow ) {
57 | this.#focusedWindow = null;
58 | }
59 | this.$dispatch( "close", win );
60 | }
61 | #onfocusinWin( win, e ) {
62 | if ( win !== this.#focusedWindow ) {
63 | const z = +win.style.zIndex || 0;
64 |
65 | this.childNodes.forEach( win => {
66 | const zz = +win.style.zIndex || 0;
67 |
68 | if ( zz > z ) {
69 | win.style.zIndex = zz - 1;
70 | }
71 | } );
72 | win.style.zIndex = this.childElementCount - 1;
73 | this.#focusedWindow = win;
74 | this.$dispatch( "focus", win.dataset.id );
75 | }
76 | }
77 | }
78 |
79 | GSUdefineElement( "gsui-windows", gsuiWindows );
80 |
--------------------------------------------------------------------------------
/test-assets/440-2.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gridsound/gs-ui-components/4aed242692aa62bfb623b374dda9ce53aecc57de/test-assets/440-2.wav
--------------------------------------------------------------------------------
/test-assets/440-simple.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gridsound/gs-ui-components/4aed242692aa62bfb623b374dda9ce53aecc57de/test-assets/440-simple.wav
--------------------------------------------------------------------------------
/test-assets/440.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gridsound/gs-ui-components/4aed242692aa62bfb623b374dda9ce53aecc57de/test-assets/440.wav
--------------------------------------------------------------------------------
/test-assets/808kick.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gridsound/gs-ui-components/4aed242692aa62bfb623b374dda9ce53aecc57de/test-assets/808kick.wav
--------------------------------------------------------------------------------
/test-assets/Cymatics-IcedOut.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gridsound/gs-ui-components/4aed242692aa62bfb623b374dda9ce53aecc57de/test-assets/Cymatics-IcedOut.wav
--------------------------------------------------------------------------------
/test-assets/Too Long - Steam Machine.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gridsound/gs-ui-components/4aed242692aa62bfb623b374dda9ce53aecc57de/test-assets/Too Long - Steam Machine.wav
--------------------------------------------------------------------------------
/test-assets/avatar.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gridsound/gs-ui-components/4aed242692aa62bfb623b374dda9ce53aecc57de/test-assets/avatar.jpg
--------------------------------------------------------------------------------
/test-assets/basssine.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gridsound/gs-ui-components/4aed242692aa62bfb623b374dda9ce53aecc57de/test-assets/basssine.wav
--------------------------------------------------------------------------------
/test-assets/clap-013.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gridsound/gs-ui-components/4aed242692aa62bfb623b374dda9ce53aecc57de/test-assets/clap-013.wav
--------------------------------------------------------------------------------
/test-assets/hat-024.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gridsound/gs-ui-components/4aed242692aa62bfb623b374dda9ce53aecc57de/test-assets/hat-024.wav
--------------------------------------------------------------------------------
/test-assets/kick-017.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gridsound/gs-ui-components/4aed242692aa62bfb623b374dda9ce53aecc57de/test-assets/kick-017.wav
--------------------------------------------------------------------------------
/test-assets/okay.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gridsound/gs-ui-components/4aed242692aa62bfb623b374dda9ce53aecc57de/test-assets/okay.wav
--------------------------------------------------------------------------------
/test-assets/openhat-012.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gridsound/gs-ui-components/4aed242692aa62bfb623b374dda9ce53aecc57de/test-assets/openhat-012.wav
--------------------------------------------------------------------------------
/test-assets/snare-018.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gridsound/gs-ui-components/4aed242692aa62bfb623b374dda9ce53aecc57de/test-assets/snare-018.wav
--------------------------------------------------------------------------------