diff --git a/css/style.css b/css/style.css new file mode 100644 index 0000000..e942692 --- /dev/null +++ b/css/style.css @@ -0,0 +1 @@ +.hidden{display:none}h1,h2,h3{font-size:420%;color:#f9d094;margin:0 0 0.1em;text-align:center;text-shadow:1px 1px 10px rgba(0,0,0,0.25)}h1 code,h2 code,h3 code{font-size:120%}h1,h2,h3,h4,h5,h6{line-height:1.1}h1{font-weight:900}h1 a,h1 a:hover{font-weight:900;color:#f9d094}h2,h3{font-weight:800;margin-top:0.5em;margin-bottom:0.1em}h2{font-size:300%}h3{font-size:125%}#default h1,#home h1,#page h1{font-size:250%;font-weight:800;padding-bottom:0.5em}#default h2,#default h3,#home h2,#home h3,#page h2,#page h3{font-weight:700;text-align:left;padding-bottom:0.3em}#default h2,#home h2,#page h2{font-size:175%}#default h3,#home h3,#page h3{font-size:150%}#default h2.disabled::before,#default a.disabled::before,#home h2.disabled::before,#home a.disabled::before,#page h2.disabled::before,#page a.disabled::before{content:"\26d4";font-family:"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";margin-right:0.3em}#default h2.deprecated::before,#default a.deprecated::before,#home h2.deprecated::before,#home a.deprecated::before,#page h2.deprecated::before,#page a.deprecated::before{content:"\26a0";font-family:"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";margin-right:0.3em}#default,#home,#page,.postcontent{font-size:1.2em;min-width:25em;max-width:35em;margin:0 auto;margin-top:1em;padding-top:1em;padding-bottom:1em}#default h1,#home h1,#page h1,.postcontent h1{text-align:left}#default img,#home img,#page img,.postcontent img{max-width:100%}#default th,#default td,#home th,#home td,#page th,#page td,.postcontent th,.postcontent td{padding:0.25em 0.5em}#information .row,#border-bottom{border-bottom:1px solid rgba(0,0,0,0.5);border-top:1px solid rgba(255,255,255,0.08);padding:2em 20px 0}html{margin:0;padding:0;font-size:62.5%;font-family:"ui-sans-serif", "-apple-system", "BlinkMacSystemFont", "Helvetica Neue", "Roboto", sans-serif;height:100%}body{height:100%;font-size:150%;line-height:1.4;color:#f9d094;background:#2e2a24;position:relative;margin:0;padding:0 30px}p{margin:0 0 1em 0}ul,ol,dl{margin-bottom:1em}ul{margin-left:20px}table{margin-bottom:1em;border-collapse:separate;border-spacing:0;border:solid rgba(0,0,0,0.4) 1px;border-radius:.4em;-moz-border-radius:.4em;-webkit-border-radius:.4em;margin-top:1em}table th,table td{padding:0.1em 1em;width:auto;max-width:25em;overflow:hidden;text-overflow:ellipsis}table .number-data{width:1%;white-space:nowrap;text-align:right}table code{font-size:130%}table tr:nth-child(odd){background:rgba(0,0,0,0.2)}table tr th{background:rgba(0,0,0,0.4)}table tr:nth-child(even){background:rgba(0,0,0,0.4)}.full-width{width:100%}div .highlight{margin-top:0}.copyable{display:flex;justify-content:center}.copyable .highlight{overflow-x:auto;margin:0}.copyable .highlight pre{border-top-right-radius:0;-moz-border-top-right-radius:0;-webkit-border-top-right-radius:0;border-bottom-right-radius:0;-moz-border-bottom-right-radius:0;-webkit-border-bottom-right-radius:0;margin:0}.copyable .highlight code::before{display:inline;content:"$ "}.copyable button{background:rgba(0,0,0,0.3);margin:0;border:none;border-left:1px solid #745626;border-top-right-radius:.4em;-moz-border-top-right-radius:.4em;-webkit-border-top-right-radius:.4em;border-bottom-right-radius:.4em;-moz-border-bottom-right-radius:.4em;-webkit-border-bottom-right-radius:.4em}.copyable button:hover{background:#745626}.install{display:flex;align-items:center}.install .label{padding-right:0.4em}pre{margin:0 0 1em 0;background:rgba(0,0,0,0.3);color:#fff;padding:8px 10px;border-radius:.4em;-moz-border-radius:.4em;-webkit-border-radius:.4em;overflow-x:auto}pre code{font-family:"ui-monospace", "SF Mono", "Monaco", "Menlo", "Consolas", monospace;font-size:11px;line-height:1.6}a{text-decoration:none;color:#be862d;font-weight:bold}a:focus{outline:1px dotted;color:#d3a459;text-decoration:underline}a:hover{color:#d3a459;text-decoration:underline}a h2,a h3{color:#be862d}a h2:hover,a h3:hover{color:#d3a459;text-decoration:underline}button,input,select,textarea,option{font-size:100%}a,a *,button,button *,select,option,label,input[type="submit"]{cursor:pointer}hr{display:none}small{font-size:90%}.group{display:block}.group:after{content:".";display:block;height:0;clear:both;visibility:hidden}sup{font-size:80%;line-height:1;vertical-align:super}button::-moz-focus-inner{border:0;padding:1px}::selection,::-moz-selection{background:#745626}#forkme{width:149px;height:149px;position:absolute;top:0;right:0;border:0}#wrap{width:57em;max-width:100%;margin:0 auto;padding:15px 0 0}#header{text-align:center;margin-bottom:1em}#language{font-size:16px;margin:1em 0}.pagination{text-align:center}.pagination a,.pagination span{display:inline-block;margin:0 0.4em}.pagination .page_number{font-style:italic}:root{--docsearch-primary-color: #be862d !important;--docsearch-modal-background: #2e2a24 !important;--docsearch-footer-background: #2e2a24 !important;--docsearch-footer-shadow: 0 -1px 0 0 rgba(0,0,0,0.5), inset 0 1px 0 0 rgba(255,255,255,0.08) !important;--docsearch-modal-shadow: 0 3px 8px 0 #2e2a24 !important;--docsearch-hit-shadow: none !important;--docsearch-hit-background: rgba(0,0,0,0.3) !important;--docsearch-hit-color: #fff !important;--docsearch-logo-color: #fff !important;--docsearch-container-background: rgba(127,127,127,0.9) !important}#search-container button.DocSearch-Button{display:inline-flex;width:17em;margin:0;border-radius:4px}.DocSearch-Logo svg .cls-1,.DocSearch-Logo svg .cls-2{fill:var(--docsearch-logo-color)}#selectable{font-size:13px}.avatar{border-radius:.4em;-moz-border-radius:.4em;-webkit-border-radius:.4em;overflow:hidden;margin-right:0.5em;vertical-align:middle}#default,#home,#page,#post,.singlepostcontent{border-top:1px solid rgba(255,255,255,0.08);box-shadow:0 -1px 0 rgba(0,0,0,0.5);-moz-box-shadow:0 -1px 0 rgba(0,0,0,0.5);-webkit-box-shadow:0 -1px 0 rgba(0,0,0,0.5)}.bottomborder{border-bottom:1px solid rgba(0,0,0,0.5)}#default code,#home code,#page code{font-size:100%;overflow-wrap:break-word}#default pre code,#home pre code,#page pre code{font-size:80%}#default li>p>code,#home li>p>code,#page li>p>code{white-space:nowrap}#information ul,.posts{list-style:none;padding:0;margin:0}#information{border-top:1px solid rgba(0,0,0,0.5)}#information .row .col-1{width:49%;float:left;padding:0 0 1em}#information .row .col-2{width:49%;float:right;padding:0 0 1em}#information .button-large{padding:2em 0 1em;font-size:120%}#information .quote{text-align:center;color:#816f51;padding-bottom:2em}#information .quote blockquote{font-size:140%;padding:0 15%}#information .quote blockquote span{font-size:140%;line-height:0.5;vertical-align:sub}#information .quote cite{font-style:normal}#information .quote cite a{font-weight:normal}#information .credits{border-bottom:none;font-size:70%;text-align:center;padding-top:1.8em}#information .credits p{opacity:0.5;margin:0;padding:0 0 0.7em}#information .button a{background:rgba(162,107,20,0.3);padding:8px 10px 6px;border-radius:.4em;-moz-border-radius:.4em;-webkit-border-radius:.4em;box-shadow:0 0 5px rgba(0,0,0,0.4);-moz-box-shadow:0 0 5px rgba(0,0,0,0.4);-webkit-box-shadow:0 0 5px rgba(0,0,0,0.4);font-size:larger}#information .button a:hover{background:rgba(162,107,20,0.25)}.button{text-align:center;margin:1em 0 2em}#border-no-bottom{border-bottom:none;font-size:70%;text-align:center;padding-top:1.8em;opacity:0.5}* html .group{height:1%}span .amp{font-weight:normal;font-style:italic;font-size:1.2em;line-height:0.8}.posts li{border-top:1px solid rgba(255,255,255,0.08);border-bottom:1px solid rgba(0,0,0,0.5);box-shadow:0 -1px 0 rgba(0,0,0,0.5);-moz-box-shadow:0 -1px 0 rgba(0,0,0,0.5);-webkit-box-shadow:0 -1px 0 rgba(0,0,0,0.5)}#latest-posts{border-top:1px solid rgba(255,255,255,0.08);border-bottom:1px solid rgba(0,0,0,0.5);padding-top:1em}#latest-posts h3{margin-top:0}#newsletter{border-top:1px solid rgba(255,255,255,0.08);margin-bottom:3em;padding:1em;text-align:center;border-radius:5px}#bd-email{margin-top:0.5em;font-size:1.2em;padding:0.1em;text-align:center;width:25em}@media only screen and (max-width: 480px){#bd-email{width:12em}}[dir="rtl"] ul{margin-left:0;margin-right:20px}[dir="rtl"] pre{direction:ltr;text-align:left}[dir="rtl"] #information .row .col-1{float:right}[dir="rtl"] #information .row .col-2{float:left}@media screen and (min-width: 700px){#information .highlight{margin-inline-end:0;-moz-margin-end:0;-webkit-margin-end:0}}@media screen and (max-width: 700px){body{padding:0}#default,#home,#page,#post,.posts{margin:0 1em}#default,#home,#page,.postcontent{min-width:0}#default h1,#home h1,#page h1,.postcontent h1{font-size:200%}.postcontent{font-size:1.1em}h1{font-size:250%}h2{font-size:150%}ul{margin-left:0;padding:0;padding-left:1em}figure{margin:0}table tr{padding:0.5em 0}table tr,table th,table td{display:block;margin:0 auto;max-width:21em;text-align:center}table .number-data{width:auto;text-align:center}#forkme{width:100px;height:100px}#information .row .col-1{width:100%;padding:0;margin:0}#information .row .col-2{width:100%;float:left}pre code#selectable{width:90%;margin:0 auto}[dir="rtl"] #information .row .col-2{float:right}}img[src$=".drawio.svg"]{background-color:white;margin-bottom:20px;padding:5%;width:90%;filter:invert(80%) sepia(60%);-webkit-filter:invert(80%) sepia(60%)}.hll{background-color:#ffc}.c{color:#999988;font-style:italic}.err{color:#a61717;background-color:#e3d2d2}.k{font-weight:bold}.o{font-weight:bold}.cm{color:#999988;font-style:italic}.cp{color:#999999;font-weight:bold}.c1{color:#999988;font-style:italic}.cs{color:#999999;font-weight:bold;font-style:italic}.gd{color:#000000;background-color:#fdd}.ge{font-style:italic}.gr{color:#a00}.gh{color:#999}.gi{color:#000000;background-color:#dfd}.go{color:#888}.gp{color:#555}.gs{font-weight:bold}.gu{color:#aaa}.gt{color:#a00}.kc{font-weight:bold}.kd{font-weight:bold}.kn{font-weight:bold}.kp{font-weight:bold}.kr{font-weight:bold}.kt{color:#445588;font-weight:bold}.m{color:#099}.s{color:#b84}.na{color:teal}.nb{color:#999}.nc{color:#999999;font-weight:bold}.no{color:#666}.ni{color:purple}.ne{color:#990000;font-weight:bold}.nf{color:#999999;font-weight:bold}.nn{color:#555}.nt{color:teal}.nv,.copyable .highlight code::before{color:teal}.ow{font-weight:bold}.w{color:#bbb}.mf{color:#099}.mh{color:#099}.mi{color:#099}.mo{color:#099}.sb{color:#b84}.sc{color:#b84}.sd{color:#b84}.s2{color:#9c7645}.se{color:#b84}.sh{color:#b84}.si{color:#b84}.sx{color:#b84}.sr{color:olive}.s1{color:#9c7645}.ss{color:#b84}.bp{color:#999}.vc{color:teal}.vg{color:teal}.vi{color:teal}.il{color:#099} diff --git a/css/style.min.css b/css/style.min.css new file mode 100644 index 0000000..05d7955 --- /dev/null +++ b/css/style.min.css @@ -0,0 +1 @@ +/*! @docsearch/css 3.9.0 | MIT License | © Algolia, Inc. and contributors | https://docsearch.algolia.com */:root{--docsearch-primary-color:#5468ff;--docsearch-text-color:#1c1e21;--docsearch-spacing:12px;--docsearch-icon-stroke-width:1.4;--docsearch-highlight-color:var(--docsearch-primary-color);--docsearch-muted-color:#969faf;--docsearch-container-background:rgba(101,108,133,.8);--docsearch-logo-color:#5468ff;--docsearch-modal-width:560px;--docsearch-modal-height:600px;--docsearch-modal-background:#f5f6f7;--docsearch-modal-shadow:inset 1px 1px 0 0 hsla(0,0%,100%,.5),0 3px 8px 0 #555a64;--docsearch-searchbox-height:56px;--docsearch-searchbox-background:#ebedf0;--docsearch-searchbox-focus-background:#fff;--docsearch-searchbox-shadow:inset 0 0 0 2px var(--docsearch-primary-color);--docsearch-hit-height:56px;--docsearch-hit-color:#444950;--docsearch-hit-active-color:#fff;--docsearch-hit-background:#fff;--docsearch-hit-shadow:0 1px 3px 0 #d4d9e1;--docsearch-key-gradient:linear-gradient(-225deg,#d5dbe4,#f8f8f8);--docsearch-key-shadow:inset 0 -2px 0 0 #cdcde6,inset 0 0 1px 1px #fff,0 1px 2px 1px rgba(30,35,90,.4);--docsearch-key-pressed-shadow:inset 0 -2px 0 0 #cdcde6,inset 0 0 1px 1px #fff,0 1px 1px 0 rgba(30,35,90,.4);--docsearch-footer-height:44px;--docsearch-footer-background:#fff;--docsearch-footer-shadow:0 -1px 0 0 #e0e3e8,0 -3px 6px 0 rgba(69,98,155,.12)}html[data-theme=dark]{--docsearch-text-color:#f5f6f7;--docsearch-container-background:rgba(9,10,17,.8);--docsearch-modal-background:#15172a;--docsearch-modal-shadow:inset 1px 1px 0 0 #2c2e40,0 3px 8px 0 #000309;--docsearch-searchbox-background:#090a11;--docsearch-searchbox-focus-background:#000;--docsearch-hit-color:#bec3c9;--docsearch-hit-shadow:none;--docsearch-hit-background:#090a11;--docsearch-key-gradient:linear-gradient(-26.5deg,#565872,#31355b);--docsearch-key-shadow:inset 0 -2px 0 0 #282d55,inset 0 0 1px 1px #51577d,0 2px 2px 0 rgba(3,4,9,.3);--docsearch-key-pressed-shadow:inset 0 -2px 0 0 #282d55,inset 0 0 1px 1px #51577d,0 1px 1px 0 #0304094d;--docsearch-footer-background:#1e2136;--docsearch-footer-shadow:inset 0 1px 0 0 rgba(73,76,106,.5),0 -4px 8px 0 rgba(0,0,0,.2);--docsearch-logo-color:#fff;--docsearch-muted-color:#7f8497}.DocSearch-Button{align-items:center;background:var(--docsearch-searchbox-background);border:0;border-radius:40px;color:var(--docsearch-muted-color);cursor:pointer;display:flex;font-weight:500;height:36px;justify-content:space-between;margin:0 0 0 16px;padding:0 8px;user-select:none}.DocSearch-Button:active,.DocSearch-Button:focus,.DocSearch-Button:hover{background:var(--docsearch-searchbox-focus-background);box-shadow:var(--docsearch-searchbox-shadow);color:var(--docsearch-text-color);outline:0}.DocSearch-Button-Container{align-items:center;display:flex}.DocSearch-Search-Icon{stroke-width:1.6}.DocSearch-Button .DocSearch-Search-Icon{color:var(--docsearch-text-color)}.DocSearch-Button-Placeholder{font-size:1rem;padding:0 12px 0 6px}.DocSearch-Button-Keys{display:flex;min-width:calc(40px + .8em)}.DocSearch-Button-Key{align-items:center;background:var(--docsearch-key-gradient);border:0;border-radius:3px;box-shadow:var(--docsearch-key-shadow);color:var(--docsearch-muted-color);display:flex;height:18px;justify-content:center;margin-right:.4em;padding:0 0 2px;position:relative;top:-1px;transition-duration:.1s;transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);width:20px}@media (prefers-reduced-motion){.DocSearch-Button-Key{transition:none}}.DocSearch-Button-Key--pressed{box-shadow:var(--docsearch-key-pressed-shadow);transform:translate3d(0,1px,0)}@media (max-width:768px){.DocSearch-Button-Keys,.DocSearch-Button-Placeholder{display:none}}.DocSearch--active{overflow:hidden!important}.DocSearch-Container,.DocSearch-Container *{box-sizing:border-box}.DocSearch-Container{background-color:var(--docsearch-container-background);height:100vh;left:0;position:fixed;top:0;width:100vw;z-index:200}.DocSearch-Container a{text-decoration:none}.DocSearch-Link{appearance:none;background:0 0;border:0;color:var(--docsearch-highlight-color);cursor:pointer;font:inherit;margin:0;padding:0}.DocSearch-Modal{background:var(--docsearch-modal-background);border-radius:6px;box-shadow:var(--docsearch-modal-shadow);flex-direction:column;margin:60px auto auto;max-width:var(--docsearch-modal-width);position:relative}.DocSearch-SearchBar{display:flex;padding:var(--docsearch-spacing) var(--docsearch-spacing) 0}.DocSearch-Form{align-items:center;background:var(--docsearch-searchbox-focus-background);border-radius:4px;box-shadow:var(--docsearch-searchbox-shadow);display:flex;height:var(--docsearch-searchbox-height);margin:0;padding:0 var(--docsearch-spacing);position:relative;width:100%}.DocSearch-Input{appearance:none;background:0 0;border:0;color:var(--docsearch-text-color);flex:1;font:inherit;font-size:1.2em;height:100%;outline:0;padding:0 0 0 8px;width:80%}.DocSearch-Input::placeholder{color:var(--docsearch-muted-color);opacity:1}.DocSearch-Input::-webkit-search-cancel-button,.DocSearch-Input::-webkit-search-decoration,.DocSearch-Input::-webkit-search-results-button,.DocSearch-Input::-webkit-search-results-decoration{display:none}.DocSearch-LoadingIndicator,.DocSearch-MagnifierLabel,.DocSearch-Reset{margin:0;padding:0}.DocSearch-MagnifierLabel,.DocSearch-Reset{align-items:center;color:var(--docsearch-highlight-color);display:flex;justify-content:center}.DocSearch-Container--Stalled .DocSearch-MagnifierLabel,.DocSearch-LoadingIndicator{display:none}.DocSearch-Container--Stalled .DocSearch-LoadingIndicator{align-items:center;color:var(--docsearch-highlight-color);display:flex;justify-content:center}@media screen and (prefers-reduced-motion:reduce){.DocSearch-Reset{animation:none;appearance:none;background:0 0;border:0;border-radius:50%;color:var(--docsearch-icon-color);cursor:pointer;right:0;stroke-width:var(--docsearch-icon-stroke-width)}}.DocSearch-Reset{animation:fade-in .1s ease-in forwards;appearance:none;background:0 0;border:0;border-radius:50%;color:var(--docsearch-icon-color);cursor:pointer;padding:2px;right:0;stroke-width:var(--docsearch-icon-stroke-width)}.DocSearch-Reset[hidden]{display:none}.DocSearch-Reset:hover{color:var(--docsearch-highlight-color)}.DocSearch-LoadingIndicator svg,.DocSearch-MagnifierLabel svg{height:24px;width:24px}.DocSearch-Cancel{display:none}.DocSearch-Dropdown{max-height:calc(var(--docsearch-modal-height) - var(--docsearch-searchbox-height) - var(--docsearch-spacing) - var(--docsearch-footer-height));min-height:var(--docsearch-spacing);overflow-y:auto;overflow-y:overlay;padding:0 var(--docsearch-spacing);scrollbar-color:var(--docsearch-muted-color) var(--docsearch-modal-background);scrollbar-width:thin}.DocSearch-Dropdown::-webkit-scrollbar{width:12px}.DocSearch-Dropdown::-webkit-scrollbar-track{background:0 0}.DocSearch-Dropdown::-webkit-scrollbar-thumb{background-color:var(--docsearch-muted-color);border:3px solid var(--docsearch-modal-background);border-radius:20px}.DocSearch-Dropdown ul{list-style:none;margin:0;padding:0}.DocSearch-Label{font-size:.75em;line-height:1.6em}.DocSearch-Help,.DocSearch-Label{color:var(--docsearch-muted-color)}.DocSearch-Help{font-size:.9em;margin:0;user-select:none}.DocSearch-Title{font-size:1.2em}.DocSearch-Logo a{display:flex}.DocSearch-Logo svg{color:var(--docsearch-logo-color);margin-left:8px}.DocSearch-Hits:last-of-type{margin-bottom:24px}.DocSearch-Hits mark{background:0 0;color:var(--docsearch-highlight-color)}.DocSearch-HitsFooter{color:var(--docsearch-muted-color);display:flex;font-size:.85em;justify-content:center;margin-bottom:var(--docsearch-spacing);padding:var(--docsearch-spacing)}.DocSearch-HitsFooter a{border-bottom:1px solid;color:inherit}.DocSearch-Hit{border-radius:4px;display:flex;padding-bottom:4px;position:relative;scroll-margin-top:40px}@media screen and (prefers-reduced-motion:reduce){.DocSearch-Hit--deleting{transition:none}}.DocSearch-Hit--deleting{opacity:0;transition:all .25s linear}@media screen and (prefers-reduced-motion:reduce){.DocSearch-Hit--favoriting{transition:none}}.DocSearch-Hit--favoriting{transform:scale(0);transform-origin:top center;transition:all .25s linear;transition-delay:.25s}.DocSearch-Hit a{background:var(--docsearch-hit-background);border-radius:4px;box-shadow:var(--docsearch-hit-shadow);display:block;padding-left:var(--docsearch-spacing);width:100%}.DocSearch-Hit-source{background:var(--docsearch-modal-background);color:var(--docsearch-highlight-color);font-size:.85em;font-weight:600;line-height:32px;margin:0 -4px;padding:8px 4px 0;position:sticky;top:0;z-index:10}.DocSearch-Hit-Tree{color:var(--docsearch-muted-color);height:var(--docsearch-hit-height);opacity:.5;stroke-width:var(--docsearch-icon-stroke-width);width:24px}.DocSearch-Hit[aria-selected=true] a{background-color:var(--docsearch-highlight-color)}.DocSearch-Hit[aria-selected=true] mark{text-decoration:underline}.DocSearch-Hit-Container{align-items:center;color:var(--docsearch-hit-color);display:flex;flex-direction:row;height:var(--docsearch-hit-height);padding:0 var(--docsearch-spacing) 0 0}.DocSearch-Hit-icon{height:20px;width:20px}.DocSearch-Hit-action,.DocSearch-Hit-icon{color:var(--docsearch-muted-color);stroke-width:var(--docsearch-icon-stroke-width)}.DocSearch-Hit-action{align-items:center;display:flex;height:22px;width:22px}.DocSearch-Hit-action svg{display:block;height:18px;width:18px}.DocSearch-Hit-action+.DocSearch-Hit-action{margin-left:6px}.DocSearch-Hit-action-button{appearance:none;background:0 0;border:0;border-radius:50%;color:inherit;cursor:pointer;padding:2px}svg.DocSearch-Hit-Select-Icon{display:none}.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-Select-Icon{display:block}.DocSearch-Hit-action-button:focus,.DocSearch-Hit-action-button:hover{background:rgba(0,0,0,.2);transition:background-color .1s ease-in}@media screen and (prefers-reduced-motion:reduce){.DocSearch-Hit-action-button:focus,.DocSearch-Hit-action-button:hover{transition:none}}.DocSearch-Hit-action-button:focus path,.DocSearch-Hit-action-button:hover path{fill:#fff}.DocSearch-Hit-content-wrapper{display:flex;flex:1 1 auto;flex-direction:column;font-weight:500;justify-content:center;line-height:1.2em;margin:0 8px;overflow-x:hidden;position:relative;text-overflow:ellipsis;white-space:nowrap;width:80%}.DocSearch-Hit-title{font-size:.9em}.DocSearch-Hit-path{color:var(--docsearch-muted-color);font-size:.75em}.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-Tree,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-action,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-icon,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-path,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-text,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-title,.DocSearch-Hit[aria-selected=true] mark{color:var(--docsearch-hit-active-color)!important}@media screen and (prefers-reduced-motion:reduce){.DocSearch-Hit-action-button:focus,.DocSearch-Hit-action-button:hover{background:rgba(0,0,0,.2);transition:none}}.DocSearch-ErrorScreen,.DocSearch-NoResults,.DocSearch-StartScreen{font-size:.9em;margin:0 auto;padding:36px 0;text-align:center;width:80%}.DocSearch-Screen-Icon{color:var(--docsearch-muted-color);padding-bottom:12px}.DocSearch-NoResults-Prefill-List{display:inline-block;padding-bottom:24px;text-align:left}.DocSearch-NoResults-Prefill-List ul{display:inline-block;padding:8px 0 0}.DocSearch-NoResults-Prefill-List li{list-style-position:inside;list-style-type:"» "}.DocSearch-Prefill{appearance:none;background:0 0;border:0;border-radius:1em;color:var(--docsearch-highlight-color);cursor:pointer;display:inline-block;font-size:1em;font-weight:700;padding:0}.DocSearch-Prefill:focus,.DocSearch-Prefill:hover{outline:0;text-decoration:underline}.DocSearch-Footer{align-items:center;background:var(--docsearch-footer-background);border-radius:0 0 8px 8px;box-shadow:var(--docsearch-footer-shadow);display:flex;flex-direction:row-reverse;flex-shrink:0;height:var(--docsearch-footer-height);justify-content:space-between;padding:0 var(--docsearch-spacing);position:relative;user-select:none;width:100%;z-index:300}.DocSearch-Commands{color:var(--docsearch-muted-color);display:flex;list-style:none;margin:0;padding:0}.DocSearch-Commands li{align-items:center;display:flex}.DocSearch-Commands li:not(:last-of-type){margin-right:.8em}.DocSearch-Commands-Key{align-items:center;background:var(--docsearch-key-gradient);border:0;border-radius:2px;box-shadow:var(--docsearch-key-shadow);color:var(--docsearch-muted-color);display:flex;height:18px;justify-content:center;margin-right:.4em;padding:0 0 1px;width:20px}.DocSearch-VisuallyHiddenForAccessibility{clip:rect(0 0 0 0);clip-path:inset(50%);height:1px;overflow:hidden;position:absolute;white-space:nowrap;width:1px}@media (max-width:768px){:root{--docsearch-spacing:10px;--docsearch-footer-height:40px}.DocSearch-Dropdown{height:100%}.DocSearch-Container{height:100vh;height:-webkit-fill-available;height:calc(var(--docsearch-vh,1vh)*100);position:absolute}.DocSearch-Footer{border-radius:0;bottom:0;position:absolute}.DocSearch-Hit-content-wrapper{display:flex;position:relative;width:80%}.DocSearch-Modal{border-radius:0;box-shadow:none;height:100vh;height:-webkit-fill-available;height:calc(var(--docsearch-vh,1vh)*100);margin:0;max-width:100%;width:100%}.DocSearch-Dropdown{max-height:calc(var(--docsearch-vh,1vh)*100 - var(--docsearch-searchbox-height) - var(--docsearch-spacing) - var(--docsearch-footer-height))}.DocSearch-Cancel{appearance:none;background:0 0;border:0;color:var(--docsearch-highlight-color);cursor:pointer;display:inline-block;flex:none;font:inherit;font-size:1em;font-weight:500;margin-left:var(--docsearch-spacing);outline:0;overflow:hidden;padding:0;user-select:none;white-space:nowrap}.DocSearch-Commands,.DocSearch-Hit-Tree{display:none}}@keyframes fade-in{0%{opacity:0}to{opacity:1}} \ No newline at end of file diff --git a/experimental/wipe2.sh b/experimental/wipe2.sh new file mode 100644 index 0000000..19d135c --- /dev/null +++ b/experimental/wipe2.sh @@ -0,0 +1,167 @@ +#!/bin/bash +# Combined ffmpeg -y commands for all static video wipes with 3-second delay between each + +# Initial list wipes +ffmpeg -y -i 0.mp4 -i 1.mp4 -filter_complex "[0:v][1:v]xfade=transition=wipeleft:duration=1.0:offset=5,format=yuv420p" -c:v libx264 -y horizontal_wipe.mp4 +sleep 3 +ffmpeg -y -i 0.mp4 -i 1.mp4 -filter_complex "[0:v][1:v]xfade=transition=wipeup:duration=1.0:offset=5,format=yuv420p" -c:v libx264 -y vertical_wipe.mp4 +sleep 3 +ffmpeg -y -i 0.mp4 -i 1.mp4 -filter_complex "[0:v][1:v]xfade=transition=diagbr:duration=1.0:offset=5,format=yuv420p" -c:v libx264 -y diagonal_topleft_bottomright_wipe.mp4 +sleep 3 +ffmpeg -y -i 0.mp4 -i 1.mp4 -filter_complex "[0:v][1:v]xfade=transition=diagbl:duration=1.0:offset=5,format=yuv420p" -c:v libx264 -y diagonal_topright_bottomleft_wipe.mp4 +sleep 3 +ffmpeg -y -i 0.mp4 -i 1.mp4 -filter_complex "[0:v][1:v]xfade=transition=circleopen:duration=1.0:offset=5,format=yuv420p" -c:v libx264 -y circular_wipe.mp4 +sleep 3 +ffmpeg -y -i 0.mp4 -i 1.mp4 -filter_complex "[0:v][1:v]xfade=transition=rectcrop:duration=1.0:offset=5,format=yuv420p" -c:v libx264 -y square_wipe.mp4 +sleep 3 +ffmpeg -y -i 0.mp4 -i 1.mp4 -i diamond_mask.png -filter_complex "[1:v][2:v]alphamerge[fg];[0:v][fg]overlay=0:0,format=yuv420p" -c:v libx264 -y diamond_wipe.mp4 +sleep 3 +ffmpeg -y -i 0.mp4 -i 1.mp4 -i star_mask.png -filter_complex "[1:v][2:v]alphamerge[fg];[0:v][fg]overlay=0:0,format=yuv420p" -c:v libx264 -y star_wipe.mp4 +sleep 3 +ffmpeg -y -i 0.mp4 -i 1.mp4 -i cross_mask.png -filter_complex "[1:v][2:v]alphamerge[fg];[0:v][fg]overlay=0:0,format=yuv420p" -c:v libx264 -y cross_wipe.mp4 +sleep 3 +ffmpeg -y -i 0.mp4 -i 1.mp4 -filter_complex "[0:v][1:v]xfade=transition=pixelize:duration=1.0:offset=5,format=yuv420p" -c:v libx264 -y checkerboard_wipe.mp4 +sleep 3 + +# Expanded list wipes +ffmpeg -y -i 0.mp4 -i 1.mp4 -filter_complex "[0:v][1:v]xfade=transition=fade:duration=1.0:offset=5,format=yuv420p" -c:v libx264 -y full_wipe.mp4 +sleep 3 +ffmpeg -y -i 0.mp4 -i 1.mp4 -filter_complex "[0:v][1:v]xfade=transition=circleopen:duration=1.0:offset=5,format=yuv420p" -c:v libx264 -y circle_wipe.mp4 +sleep 3 +ffmpeg -y -i 0.mp4 -i 1.mp4 -filter_complex "[0:v][1:v]xfade=transition=circleopen:duration=1.0:offset=5,format=yuv420p" -c:v libx264 -y iris_circle_wipe.mp4 +sleep 3 +ffmpeg -y -i 0.mp4 -i 1.mp4 -filter_complex "[0:v][1:v]xfade=transition=circleopen:duration=1.0:offset=5,format=yuv420p" -c:v libx264 -y ellipse_wipe.mp4 +sleep 3 +ffmpeg -y -i 0.mp4 -i 1.mp4 -filter_complex "[0:v][1:v]xfade=transition=clock:duration=1.0:offset=5,format=yuv420p" -c:v libx264 -y clock_wipe.mp4 +sleep 3 +ffmpeg -y -i 0.mp4 -i 1.mp4 -filter_complex "[0:v][1:v]xfade=transition=circleopen:duration=1.0:offset=5,format=yuv420p" -c:v libx264 -y reveal_circle_wipe.mp4 +sleep 3 +ffmpeg -y -i 0.mp4 -i 1.mp4 -i triangle_mask.png -filter_complex "[1:v][2:v]alphamerge[fg];[0:v][fg]overlay=0:0,format=yuv420p" -c:v libx264 -y triangle_wipe.mp4 +sleep 3 +ffmpeg -y -i 0.mp4 -i 1.mp4 -i triangle_mask.png -filter_complex "[1:v][2:v]alphamerge[fg];[0:v][fg]overlay=0:0,format=yuv420p" -c:v libx264 -y reveal_triangle_wipe.mp4 +sleep 3 +ffmpeg -y -i 0.mp4 -i 1.mp4 -filter_complex "[0:v][1:v]xfade=transition=wipeleft:duration=1.0:offset=5,format=yuv420p" -c:v libx264 -y half_wipe.mp4 +sleep 3 +ffmpeg -y -i 0.mp4 -i 1.mp4 -filter_complex "[0:v][1:v]xfade=transition=rectcrop:duration=1.0:offset=5,format=yuv420p" -c:v libx264 -y iris_square_wipe.mp4 +sleep 3 +ffmpeg -y -i 0.mp4 -i 1.mp4 -filter_complex "[0:v][1:v]xfade=transition=rectcrop:duration=1.0:offset=5,format=yuv420p" -c:v libx264 -y rectangle_wipe.mp4 +sleep 3 +ffmpeg -y -i 0.mp4 -i 1.mp4 -filter_complex "[0:v][1:v]xfade=transition=rectcrop:duration=1.0:offset=5,format=yuv420p" -c:v libx264 -y reveal_square_wipe.mp4 +sleep 3 +ffmpeg -y -i 0.mp4 -i 1.mp4 -i star_mask.png -filter_complex "[1:v][2:v]alphamerge[fg];[0:v][fg]overlay=0:0,format=yuv420p" -c:v libx264 -y reveal_star_wipe.mp4 +sleep 3 +ffmpeg -y -i 0.mp4 -i 1.mp4 -i heart_mask.png -filter_complex "[1:v][2:v]alphamerge[fg];[0:v][fg]overlay=0:0,format=yuv420p" -c:v libx264 -y heart_wipe.mp4 +sleep 3 +ffmpeg -y -i 0.mp4 -i 1.mp4 -i pentagon_mask.png -filter_complex "[1:v][2:v]alphamerge[fg];[0:v][fg]overlay=0:0,format=yuv420p" -c:v libx264 -y pentagon_wipe.mp4 +sleep 3 +ffmpeg -y -i 0.mp4 -i 1.mp4 -i hexagon_mask.png -filter_complex "[1:v][2:v]alphamerge[fg];[0:v][fg]overlay=0:0,format=yuv420p" -c:v libx264 -y hexagon_wipe.mp4 +sleep 3 +ffmpeg -y -i 0.mp4 -i 1.mp4 -i octagon_mask.png -filter_complex "[1:v][2:v]alphamerge[fg];[0:v][fg]overlay=0:0,format=yuv420p" -c:v libx264 -y octagon_wipe.mp4 +sleep 3 +ffmpeg -y -i 0.mp4 -i 1.mp4 -i parallelogram_mask.png -filter_complex "[1:v][2:v]alphamerge[fg];[0:v][fg]overlay=0:0,format=yuv420p" -c:v libx264 -y parallelogram_wipe.mp4 +sleep 3 +ffmpeg -y -i 0.mp4 -i 1.mp4 -i chevron_mask.png -filter_complex "[1:v][2:v]alphamerge[fg];[0:v][fg]overlay=0:0,format=yuv420p" -c:v libx264 -y chevron_wipe.mp4 +sleep 3 +ffmpeg -y -i 0.mp4 -i 1.mp4 -filter_complex "[0:v][1:v]xfade=transition=diagbr:duration=1.0:offset=5,format=yuv420p" -c:v libx264 -y diagonal_linear_wipe.mp4 +sleep 3 +ffmpeg -y -i 0.mp4 -i 1.mp4 -filter_complex "[0:v][1:v]xfade=transition=diagbl:duration=1.0:offset=5,format=yuv420p" -c:v libx264 -y split_diagonal_wipe.mp4 +sleep 3 +ffmpeg -y -i 0.mp4 -i 1.mp4 -filter_complex "[0:v][1:v]xfade=transition=radial:duration=1.0:offset=5,format=yuv420p" -c:v libx264 -y angular_shutter_wipe.mp4 +sleep 3 +ffmpeg -y -i 0.mp4 -i 1.mp4 -i zigzag_mask.png -filter_complex "[1:v][2:v]alphamerge[fg];[0:v][fg]overlay=0:0,format=yuv420p" -c:v libx264 -y zigzag_wipe.mp4 +sleep 3 +ffmpeg -y -i 0.mp4 -i 1.mp4 -i sawtooth_mask.png -filter_complex "[1:v][2:v]alphamerge[fg];[0:v][fg]overlay=0:0,format=yuv420p" -c:v libx264 -y sawtooth_wipe.mp4 +sleep 3 +ffmpeg -y -i 0.mp4 -i 1.mp4 -filter_complex "[0:v][1:v]xfade=transition=pixelize:duration=1.0:offset=5,format=yuv420p" -c:v libx264 -y grid_wipe.mp4 +sleep 3 +ffmpeg -y -i 0.mp4 -i 1.mp4 -i honeycomb_mask.png -filter_complex "[1:v][2:v]alphamerge[fg];[0:v][fg]overlay=0:0,format=yuv420p" -c:v libx264 -y honeycomb_wipe.mp4 +sleep 3 +ffmpeg -y -i 0.mp4 -i 1.mp4 -i starfield_mask.png -filter_complex "[1:v][2:v]alphamerge[fg];[0:v][fg]overlay=0:0,format=yuv420p" -c:v libx264 -y starfield_wipe.mp4 +sleep 3 +ffmpeg -y -i 0.mp4 -i 1.mp4 -filter_complex "[0:v][1:v]xfade=transition=pixelize:duration=1.0:offset=5,format=yuv420p" -c:v libx264 -y mosaic_wipe.mp4 +sleep 3 +ffmpeg -y -i 0.mp4 -i 1.mp4 -filter_complex "[0:v][1:v]xfade=transition=hlr:duration=1.0:offset=5,format=yuv420p" -c:v libx264 -y barn_door_h_wipe.mp4 +sleep 3 +ffmpeg -y -i 0.mp4 -i 1.mp4 -filter_complex "[0:v][1:v]xfade=transition=vud:duration=1.0:offset=5,format=yuv420p" -c:v libx264 -y barn_door_v_w + +ipe.mp4 +sleep 3 +ffmpeg -y -i 0.mp4 -i 1.mp4 -i four_panel_mask.png -filter_complex "[1:v][2:v]alphamerge[fg];[0:v][fg]overlay=0:0,format=yuv420p" -c:v libx264 -y four_panel_wipe.mp4 +sleep 3 +ffmpeg -y -i 0.mp4 -i 1.mp4 -filter_complex "[0:v][1:v]xfade=transition=hblur:duration=1.0:offset=5,format=yuv420p" -c:v libx264 -y blinds_h_wipe.mp4 +sleep 3 +ffmpeg -y -i 0.mp4 -i 1.mp4 -filter_complex "[0:v][1:v]xfade=transition=vblur:duration=1.0:offset=5,format=yuv420p" -c:v libx264 -y blinds_v_wipe.mp4 +sleep 3 +ffmpeg -y -i 0.mp4 -i 1.mp4 -filter_complex "[0:v][1:v]xfade=transition=radial:duration=1.0:offset=5,format=yuv420p" -c:v libx264 -y fan_blades_wipe.mp4 +sleep 3 +ffmpeg -y -i 0.mp4 -i 1.mp4 -filter_complex "[0:v][1:v]xfade=transition=clock:duration=1.0:offset=5,format=yuv420p" -c:v libx264 -y clock_hands_wipe.mp4 +sleep 3 +ffmpeg -y -i 0.mp4 -i 1.mp4 -filter_complex "[0:v][1:v]xfade=transition=circleopen:duration=1.0:offset=5,format=yuv420p" -c:v libx264 -y curved_arc_wipe.mp4 +sleep 3 +ffmpeg -y -i 0.mp4 -i 1.mp4 -i page_curl_mask.png -filter_complex "[1:v][2:v]alphamerge[fg];[0:v][fg]overlay=0:0,format=yuv420p" -c:v libx264 -y page_curl_wipe.mp4 +sleep 3 +ffmpeg -y -i 0.mp4 -i 1.mp4 -i flipboard_mask.png -filter_complex "[1:v][2:v]alphamerge[fg];[0:v][fg]overlay=0:0,format=yuv420p" -c:v libx264 -y flipboard_wipe.mp4 +sleep 3 +ffmpeg -y -i 0.mp4 -i 1.mp4 -filter_complex "[0:v][1:v]xfade=transition=hblur:duration=1.0:offset=5,format=yuv420p" -c:v libx264 -y louver_wipe.mp4 +sleep 3 +ffmpeg -y -i 0.mp4 -i 1.mp4 -i sliding_polygon_mask.png -filter_complex "[1:v][2:v]alphamerge[fg];[0:v][fg]overlay=0:0,format=yuv420p" -c:v libx264 -y sliding_polygon_wipe.mp4 +sleep 3 +ffmpeg -y -i 0.mp4 -i 1.mp4 -i fractal_mask.png -filter_complex "[1:v][2:v]alphamerge[fg];[0:v][fg]overlay=0:0,format=yuv420p" -c:v libx264 -y fractal_wipe.mp4 +sleep 3 +ffmpeg -y -i 0.mp4 -i 1.mp4 -filter_complex "[0:v][1:v]xfade=transition=pixelize:duration=1.0:offset=5,format=yuv420p" -c:v libx264 -y fade_grid_wipe.mp4 +sleep 3 +ffmpeg -y -i 0.mp4 -i 1.mp4 -i cube_spin_mask.png -filter_complex "[1:v][2:v]alphamerge[fg];[0:v][fg]overlay=0:0,format=yuv420p" -c:v libx264 -y cube_spin_wipe.mp4 +sleep 3 +ffmpeg -y -i 0.mp4 -i 1.mp4 -i card_flip_mask.png -filter_complex "[1:v][2:v]alphamerge[fg];[0:v][fg]overlay=0:0,format=yuv420p" -c:v libx264 -y card_flip_wipe.mp4 +sleep 3 +ffmpeg -y -i 0.mp4 -i 1.mp4 -i polygon_tunnel_mask.png -filter_complex "[1:v][2:v]alphamerge[fg];[0:v][fg]overlay=0:0,format=yuv420p" -c:v libx264 -y polygon_tunnel_wipe.mp4 +sleep 3 +ffmpeg -y -i 0.mp4 -i 1.mp4 -i prism_fold_mask.png -filter_complex "[1:v][2:v]alphamerge[fg];[0:v][fg]overlay=0:0,format=yuv420p" -c:v libx264 -y prism_fold_wipe.mp4 +sleep 3 +ffmpeg -y -i 0.mp4 -i 1.mp4 -i svg_mask.png -filter_complex "[1:v][2:v]alphamerge[fg];[0:v][fg]overlay=0:0,format=yuv420p" -c:v libx264 -y svg_mask_wipe.mp4 +sleep 3 +ffmpeg -y -i 0.mp4 -i 1.mp4 -i text_reveal_mask.png -filter_complex "[1:v][2:v]alphamerge[fg];[0:v][fg]overlay=0:0,format=yuv420p" -c:v libx264 -y text_reveal_wipe.mp4 +sleep 3 +ffmpeg -y -i 0.mp4 -i 1.mp4 -i logo_mask.png -filter_complex "[1:v][2:v]alphamerge[fg];[0:v][fg]overlay=0:0,format=yuv420p" -c:v libx264 -y logo_wipe.mp4 +sleep 3 +ffmpeg -y -i 0.mp4 -i 1.mp4 -filter_complex "[0:v][1:v]xfade=transition=rectcrop:duration=1.0:offset=5,format=yuv420p" -c:v libx264 -y letterboxed_wipe.mp4 +sleep 3 +ffmpeg -y -i 0.mp4 -i 1.mp4 -filter_complex "[0:v][1:v]xfade=transition=radial:duration=1.0:offset=5,format=yuv420p" -c:v libx264 -y angular_burst_wipe.mp4 +sleep 3 +ffmpeg -y -i 0.mp4 -i 1.mp4 -i polygon_scatter_mask.png -filter_complex "[1:v][2:v]alphamerge[fg];[0:v][fg]overlay=0:0,format=yuv420p" -c:v libx264 -y polygon_scatter_wipe.mp4 +sleep 3 +ffmpeg -y -i 0.mp4 -i 1.mp4 -i blade_slash_mask.png -filter_complex "[1:v][2:v]alphamerge[fg];[0:v][fg]overlay=0:0,format=yuv420p" -c:v libx264 -y blade_slash_wipe.mp4 +sleep 3 +ffmpeg -y -i 0.mp4 -i 1.mp4 -filter_complex "[0:v][1:v]xfade=transition=radial:duration=1.0:offset=5,format=yuv420p" -c:v libx264 -y rotating_window_wipe.mp4 +sleep 3 +ffmpeg -y -i 0.mp4 -i 1.mp4 -filter_complex "[0:v][1:v]xfade=transition=radial:duration=1.0:offset=5,format=yuv420p" -c:v libx264 -y radial_wipe.mp4 +sleep 3 +ffmpeg -y -i 0.mp4 -i 1.mp4 -filter_complex "[0:v][1:v]xfade=transition=wipeleft:duration=1.0:offset=5,format=yuv420p" -c:v libx264 -y bar_h_wipe.mp4 +sleep 3 +ffmpeg -y -i 0.mp4 -i 1.mp4 -filter_complex "[0:v][1:v]xfade=transition=wipeup:duration=1.0:offset=5,format=yuv420p" -c:v libx264 -y bar_v_wipe.mp4 +sleep 3 +ffmpeg -y -i 0.mp4 -i 1.mp4 -filter_complex "[0:v][1:v]xfade=transition=hblur:duration=1.0:offset=5,format=yuv420p" -c:v libx264 -y venetian_wipe.mp4 +sleep 3 +ffmpeg -y -i 0.mp4 -i 1.mp4 -filter_complex "[0:v][1:v]xfade=transition=vblur:duration=1.0:offset=5,format=yuv420p" -c:v libx264 -y window_blind_wipe.mp4 +sleep 3 +ffmpeg -y -i 0.mp4 -i 1.mp4 -filter_complex "[0:v][1:v]xfade=transition=hlr:duration=1.0:offset=5,format=yuv420p" -c:v libx264 -y door_h_wipe.mp4 +sleep 3 +ffmpeg -y -i 0.mp4 -i 1.mp4 -filter_complex "[0:v][1:v]xfade=transition=vud:duration=1.0:offset=5,format=yuv420p" -c:v libx264 -y door_v_wipe.mp4 +sleep 3 +ffmpeg -y -i 0.mp4 -i 1.mp4 -i page_peel_mask.png -filter_complex "[1:v][2:v]alphamerge[fg];[0:v][fg]overlay=0:0,format=yuv420p" -c:v libx264 -y page_peel_wipe.mp4 +sleep 3 +ffmpeg -y -i 0.mp4 -i 1.mp4 -filter_complex "[0:v][1:v]xfade=transition=zoom:duration=1.0:offset=5,format=yuv420p" -c:v libx264 -y zoom_in_wipe.mp4 +sleep 3 +ffmpeg -y -i 0.mp4 -i 1.mp4 -filter_complex "[0:v][1:v]xfade=transition=zoom:duration=1.0:offset=5,format=yuv420p" -c:v libx264 -y zoom_out_wipe.mp4 +sleep 3 +ffmpeg -y -i 0.mp4 -i 1.mp4 -filter_complex "[0:v][1:v]xfade=transition=wipeleft:duration=1.0:offset=5,format=yuv420p" -c:v libx264 -y push_left_wipe.mp4 +sleep 3 +ffmpeg -y -i 0.mp4 -i 1.mp4 -filter_complex "[0:v][1:v]xfade=transition=wiperight:duration=1.0:offset=5,format=yuv420p" -c:v libx264 -y push_right_wipe.mp4 +sleep 3 +ffmpeg -y -i 0.mp4 -i 1.mp4 -filter_complex "[0:v][1:v]xfade=transition=wipeup:duration=1.0:offset=5,format=yuv420p" -c:v libx264 -y push_up_wipe.mp4 +sleep 3 +ffmpeg -y -i 0.mp4 -i 1.mp4 -filter_complex "[0:v][1:v]xfade=transition=wipedown:duration=1.0:offset=5,format=yuv420p" -c:v libx264 -y push_down_wipe.mp4 +sleep 3 +ffmpeg -y -i 0.mp4 -i 1.mp4 -filter_complex "[0:v][1:v]xfade=transition=radial:duration=1.0:offset=5,format=yuv420p" -c:v libx264 -y spiral_wipe.mp4 +sleep 3 +ffmpeg -y -i 0.mp4 -i 1.mp4 -i wave_mask.png -filter_complex "[1:v][2:v]alphamerge[fg];[0:v][fg]overlay=0:0,format=yuv420p" -c:v libx264 -y wave_wipe.mp4 \ No newline at end of file diff --git a/experimental/wipercheck.sh b/experimental/wipercheck.sh new file mode 100644 index 0000000..6af174b --- /dev/null +++ b/experimental/wipercheck.sh @@ -0,0 +1,34 @@ +#!/bin/bash +ffmpeg -i 0.mp4 -i 1.mp4 -filter_complex "[0:v][1:v]xfade=transition=wipeleft:duration=1:offset=5,format=yuv420p" -c:v libx264 -y horizontal_wipe.mp4 +sleep 2 +ffmpeg -i 0.mp4 -i 1.mp4 -filter_complex "[0:v][1:v]xfade=transition=wipeup:duration=1:offset=5,format=yuv420p" -c:v libx264 -y vertical_wipe.mp4 +sleep 2 +ffmpeg -i 0.mp4 -i 1.mp4 -filter_complex "[0:v][1:v]xfade=transition=diagbr:duration=1:offset=5,format=yuv420p" -c:v libx264 -y diagonal_topleft_bottomright_wipe.mp4 +sleep 2 +#!/bin/bash +ffmpeg -i 0.mp4 -i 1.mp4 -filter_complex "[0:v][1:v]xfade=transition=diagbl:duration=1:offset=5,format=yuv420p" -c:v libx264 -y diagonal_topright_bottomleft_wipe.mp4 +sleep 2 +#!/bin/bash +ffmpeg -i 0.mp4 -i 1.mp4 -filter_complex "[0:v][1:v]xfade=transition=circleopen:duration=1:offset=5,format=yuv420p" -c:v libx264 -y circular_wipe.mp4 +sleep 2 +#!/bin/bash +ffmpeg -i 0.mp4 -i 1.mp4 -filter_complex "[0:v][1:v]xfade=transition=rectcrop:duration=1:offset=5,format=yuv420p" -c:v libx264 -y square_wipe.mp4 +sleep 2 +#!/bin/bash +# Note: FFmpeg's xfade does not have a direct diamond wipe. Approximating with custom mask. +# Create a diamond-shaped mask image (white diamond on black background) named diamond_mask.png +ffmpeg -i 0.mp4 -i 1.mp4 -i diamond_mask.png -filter_complex "[1:v][2:v]alphamerge[fg];[0:v][fg]overlay=0:0,format=yuv420p" -c:v libx264 -y diamond_wipe.mp4 +sleep 2 +#!/bin/bash +# Note: FFmpeg's xfade does not support star wipe. Requires custom star-shaped mask. +# Create a star-shaped mask image (white star on black background) named star_mask.png +ffmpeg -i 0.mp4 -i 1.mp4 -i star_mask.png -filter_complex "[1:v][2:v]alphamerge[fg];[0:v][fg]overlay=0:0,format=yuv420p" -c:v libx264 -y star_wipe.mp4 +sleep 2 +#!/bin/bash +# Note: FFmpeg's xfade does not support cross wipe. Approximating with custom mask. +# Create a cross-shaped mask image (white cross on black background) named cross_mask.png +ffmpeg -i 0.mp4 -i 1.mp4 -i cross_mask.png -filter_complex "[1:v][2:v]alphamerge[fg];[0:v][fg]overlay=0:0,format=yuv420p" -c:v libx264 -y cross_wipe.mp4 +sleep 2 +#!/bin/bash +# Note: FFmpeg's xfade does not support checkerboard wipe. Approximating with pixelize filter. +ffmpeg -i 0.mp4 -i 1.mp4 -filter_complex "[0:v][1:v]xfade=transition=pixelize:duration=1:offset=5,format=yuv420p" -c:v libx264 -y checkerboard_wipe.mp4 \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 0000000..c8122f8 --- /dev/null +++ b/index.html @@ -0,0 +1,201 @@ + + + + + + MySoftware - The Missing Package Manager + + + +
+
+ +

MySoftware

+

The Missing Package Manager for Your System

+
+
+ +
+
+

Installation

+

Paste that in a macOS Terminal or Linux shell prompt.

+
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/MySoftware/install/main/install.sh)"
+

The script explains what it will do and then pauses before it does it. Read about other installation options.

+
+
+ +
+
+

What Does videobeaux Do?

+
+
+

MySoftware installs the stuff you need that your system didn’t.

+
+
+
mysoftware install package
+
+
+
+ +
+
+
+

MySoftware installs the stuff you need that your system didn’t.

+
+
+
mysoftware install package
+
+
+
+ +
+ + + + \ No newline at end of file diff --git a/lagkage_layouts/layout.json b/lagkage_layouts/layout.json new file mode 100644 index 0000000..0158e35 --- /dev/null +++ b/lagkage_layouts/layout.json @@ -0,0 +1,39 @@ +{ + "sequence_direction": "forward", + "layers": [ + { + "layer_number": 1, + "name": "logo", + "filename": "media/mask8.png", + "type": "img", + "mode": "place", + "place": "top_right", + "size": 20, + "opacity": 0.85, + "blend_mode": "normal" + }, + { + "layer_number": 2, + "name": "corner_camera", + "filename": "media/schwwaaa.mp4", + "type": "video", + "mode": "free", + "pos_x": 120, + "pos_y": 200, + "size": 35, + "opacity": 0.7, + "blend_mode": "normal" + }, + { + "layer_number": 3, + "name": "animated_sticker", + "filename": "media/media.gif", + "type": "gif", + "mode": "place", + "place": "bottom_left", + "size": 15, + "opacity": 0.6, + "blend_mode": "normal" + } + ] +} diff --git a/lagkage_layouts/layout_big.json b/lagkage_layouts/layout_big.json new file mode 100644 index 0000000..fbbd3e9 --- /dev/null +++ b/lagkage_layouts/layout_big.json @@ -0,0 +1,108 @@ +{ + "sequence_direction": "forward", + "layers": [ + { + "layer_number": 1, + "name": "top_right_logo", + "filename": "media/reem.png", + "type": "img", + "mode": "place", + "place": "top_right", + "size": 18, + "opacity": 0.95, + "blend_mode": "normal" + }, + { + "layer_number": 2, + "name": "top_left_bug", + "filename": "media/screen.png", + "type": "img", + "mode": "place", + "place": "top_left", + "size": 10, + "opacity": 0.8, + "blend_mode": "normal" + }, + { + "layer_number": 3, + "name": "pip_camera_a", + "filename": "media/schwwaaa.mp4", + "type": "video", + "mode": "free", + "pos_x": 80, + "pos_y": 80, + "size": 28, + "opacity": 1.0, + "blend_mode": "normal" + }, + { + "layer_number": 4, + "name": "pip_camera_b", + "filename": "media/faith.mp4", + "type": "video", + "mode": "free", + "pos_x": 80, + "pos_y": 420, + "size": 28, + "opacity": 1.0, + "blend_mode": "normal" + }, + { + "layer_number": 5, + "name": "right_side_vertical_bar", + "filename": "media/mask1.png", + "type": "img", + "mode": "place", + "place": "center_right", + "size": 12, + "opacity": 0.9, + "blend_mode": "normal" + }, + { + "layer_number": 6, + "name": "lower_third_plate", + "filename": "media/gross.png", + "type": "img", + "mode": "place", + "place": "bottom_center", + "size": 60, + "opacity": 0.95, + "blend_mode": "normal" + }, + { + "layer_number": 7, + "name": "looping_sticker_left", + "filename": "media/circus.gif", + "type": "gif", + "mode": "free", + "pos_x": 120, + "pos_y": 260, + "size": 14, + "opacity": 1.0, + "blend_mode": "normal" + }, + { + "layer_number": 8, + "name": "looping_sticker_right", + "filename": "media/bunny.gif", + "type": "gif", + "mode": "free", + "pos_x": 1520, + "pos_y": 260, + "size": 14, + "opacity": 1.0, + "blend_mode": "normal" + }, + { + "layer_number": 9, + "name": "full_frame_vhs_noise", + "filename": "media/media.gif", + "type": "gif", + "mode": "place", + "place": "center", + "size": 100, + "opacity": 0.35, + "blend_mode": "normal" + } + ] +} diff --git a/lagkage_layouts/layout_big_2.json b/lagkage_layouts/layout_big_2.json new file mode 100644 index 0000000..217be3c --- /dev/null +++ b/lagkage_layouts/layout_big_2.json @@ -0,0 +1,112 @@ +{ + "sequence_direction": "forward", + "layers": [ + { + "layer_number": 1, + "name": "top_right_logo_floating", + "filename": "media/reem.png", + "type": "img", + "mode": "free", + "pos_x": 1430, + "pos_y": 70, + "size": 14, + "opacity": 0.95, + "blend_mode": "normal" + }, + { + "layer_number": 2, + "name": "offset_corner_bug", + "filename": "media/screen.png", + "type": "img", + "mode": "free", + "pos_x": 90, + "pos_y": 40, + "size": 12, + "opacity": 0.8, + "blend_mode": "normal" + }, + { + "layer_number": 3, + "name": "pip_camera_a_small_top", + "filename": "media/schwwaaa.mp4", + "type": "video", + "mode": "free", + "pos_x": 260, + "pos_y": 120, + "size": 22, + "opacity": 1.0, + "blend_mode": "normal" + }, + { + "layer_number": 4, + "name": "pip_camera_b_large_bottom", + "filename": "media/faith.mp4", + "type": "video", + "mode": "free", + "pos_x": 1080, + "pos_y": 530, + "size": 36, + "opacity": 0.95, + "blend_mode": "normal" + }, + { + "layer_number": 5, + "name": "angled_mask_mid_left", + "filename": "media/mask1.png", + "type": "img", + "mode": "free", + "pos_x": 160, + "pos_y": 360, + "size": 26, + "opacity": 0.9, + "blend_mode": "normal" + }, + { + "layer_number": 6, + "name": "lower_third_plate_offset", + "filename": "media/gross.png", + "type": "img", + "mode": "free", + "pos_x": 260, + "pos_y": 780, + "size": 54, + "opacity": 0.95, + "blend_mode": "normal" + }, + { + "layer_number": 7, + "name": "looping_sticker_left_mid", + "filename": "media/circus.gif", + "type": "gif", + "mode": "free", + "pos_x": 220, + "pos_y": 260, + "size": 18, + "opacity": 1.0, + "blend_mode": "normal" + }, + { + "layer_number": 8, + "name": "looping_sticker_right_high", + "filename": "media/bunny.gif", + "type": "gif", + "mode": "free", + "pos_x": 1380, + "pos_y": 180, + "size": 11, + "opacity": 1.0, + "blend_mode": "normal" + }, + { + "layer_number": 9, + "name": "full_frame_vhs_noise_soft", + "filename": "media/media.gif", + "type": "gif", + "mode": "place", + "place": "center", + "size": 115, + "opacity": 0.3, + "blend_mode": "normal" + } + ] +} diff --git a/lagkage_layouts/layout_big_3.json b/lagkage_layouts/layout_big_3.json new file mode 100644 index 0000000..ef4d549 --- /dev/null +++ b/lagkage_layouts/layout_big_3.json @@ -0,0 +1,111 @@ +{ + "sequence_direction": "forward", + "layers": [ + { + "layer_number": 1, + "name": "logo_top_right", + "filename": "media/reem.png", + "type": "img", + "mode": "place", + "place": "top_right", + "size": 16, + "opacity": 0.95, + "blend_mode": "normal" + }, + { + "layer_number": 2, + "name": "screen_near_top_center", + "filename": "media/screen.png", + "type": "img", + "mode": "free", + "pos_x": 420, + "pos_y": 60, + "size": 12, + "opacity": 0.8, + "blend_mode": "normal" + }, + { + "layer_number": 3, + "name": "pip_camera_a_left_mid", + "filename": "media/schwwaaa.mp4", + "type": "video", + "mode": "free", + "pos_x": 120, + "pos_y": 160, + "size": 24, + "opacity": 1.0, + "blend_mode": "normal" + }, + { + "layer_number": 4, + "name": "pip_camera_b_right_lower", + "filename": "media/faith.mp4", + "type": "video", + "mode": "free", + "pos_x": 1120, + "pos_y": 520, + "size": 32, + "opacity": 0.95, + "blend_mode": "normal" + }, + { + "layer_number": 5, + "name": "mask_left_edge_half_off", + "filename": "media/mask1.png", + "type": "img", + "mode": "free", + "pos_x": -80, + "pos_y": 340, + "size": 22, + "opacity": 0.9, + "blend_mode": "normal" + }, + { + "layer_number": 6, + "name": "gross_lower_band", + "filename": "media/gross.png", + "type": "img", + "mode": "free", + "pos_x": 260, + "pos_y": 800, + "size": 52, + "opacity": 0.95, + "blend_mode": "normal" + }, + { + "layer_number": 7, + "name": "circus_sticker_top_half_off", + "filename": "media/circus.gif", + "type": "gif", + "mode": "free", + "pos_x": 220, + "pos_y": -40, + "size": 16, + "opacity": 1.0, + "blend_mode": "normal" + }, + { + "layer_number": 8, + "name": "bunny_sticker_right_mid", + "filename": "media/bunny.gif", + "type": "gif", + "mode": "free", + "pos_x": 1460, + "pos_y": 260, + "size": 12, + "opacity": 1.0, + "blend_mode": "normal" + }, + { + "layer_number": 9, + "name": "full_frame_vhs_noise", + "filename": "media/media.gif", + "type": "gif", + "mode": "place", + "place": "center", + "size": 110, + "opacity": 0.3, + "blend_mode": "normal" + } + ] +} diff --git a/lagkage_layouts/layout_big_4.json b/lagkage_layouts/layout_big_4.json new file mode 100644 index 0000000..2f90dc7 --- /dev/null +++ b/lagkage_layouts/layout_big_4.json @@ -0,0 +1,111 @@ +{ + "sequence_direction": "forward", + "layers": [ + { + "layer_number": 1, + "name": "logo_top_right_free", + "filename": "../media/reem.png", + "type": "img", + "mode": "free", + "pos_x": 20, + "pos_y": 420, + "size": 30, + "opacity": 0.95, + "blend_mode": "normal" + }, + { + "layer_number": 2, + "name": "screen_top_left_free", + "filename": "../media/screen.png", + "type": "img", + "mode": "free", + "pos_x": 10, + "pos_y": 210, + "size": 50, + "opacity": 0.8, + "blend_mode": "normal" + }, + { + "layer_number": 3, + "name": "pip_camera_a_left_mid_free", + "filename": "../media/schwwaaa.mp4", + "type": "video", + "mode": "place", + "place": "top_right", + "size": 40, + "opacity": 1.0, + "blend_mode": "normal" + }, + { + "layer_number": 4, + "name": "pip_camera_b_right_low_free", + "filename": "../media/faith.mp4", + "type": "video", + "mode": "place", + "place": "top_left", + "size": 34, + "opacity": 0.95, + "blend_mode": "normal" + }, + { + "layer_number": 5, + "name": "mask_left_edge_half_off_free", + "filename": "../media/mask1.png", + "type": "img", + "mode": "free", + "pos_x": 450, + "pos_y": 360, + "size": 22, + "opacity": 0.9, + "blend_mode": "normal" + }, + { + "layer_number": 6, + "name": "gross_lower_band_free", + "filename": "../media/gross.png", + "type": "img", + "mode": "free", + "pos_x": 180, + "pos_y": 180, + "size": 25, + "opacity": 0.95, + "blend_mode": "normal" + }, + { + "layer_number": 7, + "name": "circus_sticker_top_center_free", + "filename": "../media/circus.gif", + "type": "gif", + "mode": "free", + "pos_x": 60, + "pos_y": 260, + "size": 50, + "opacity": 1.0, + "blend_mode": "normal" + }, + { + "layer_number": 8, + "name": "bunny_sticker_right_mid_free", + "filename": "../media/bunny.gif", + "type": "gif", + "mode": "free", + "pos_x": 50, + "pos_y": 365, + "size": 75, + "opacity": 1.0, + "blend_mode": "normal" + }, + { + "layer_number": 9, + "name": "vhs_noise_center_free", + "filename": "../media/media.gif", + "type": "gif", + "mode": "free", + "pos_x": 175, + "pos_y": 350, + "size": 60, + "opacity": 0.3, + "blend_mode": "normal" + } + ] +} diff --git a/lagkage_layouts/layout_big_5.json b/lagkage_layouts/layout_big_5.json new file mode 100644 index 0000000..ddb1362 --- /dev/null +++ b/lagkage_layouts/layout_big_5.json @@ -0,0 +1,87 @@ +{ + "sequence_direction": "forward", + "layers": [ + { + "layer_number": 1, + "name": "logo_top_right_free", + "filename": "../media/reem.png", + "type": "img", + "mode": "free", + "pos_x": 20, + "pos_y": 420, + "size": 30, + "opacity": 0.95, + "blend_mode": "normal" + }, + { + "layer_number": 3, + "name": "pip_camera_a_left_mid_free", + "filename": "../media/schwwaaa.mp4", + "type": "video", + "mode": "place", + "place": "top_right", + "size": 40, + "opacity": 1.0, + "blend_mode": "normal" + }, + { + "layer_number": 4, + "name": "pip_camera_b_right_low_free", + "filename": "../media/faith.mp4", + "type": "video", + "mode": "place", + "place": "top_left", + "size": 34, + "opacity": 0.95, + "blend_mode": "normal" + }, + { + "layer_number": 6, + "name": "gross_lower_band_free", + "filename": "../media/gross.png", + "type": "img", + "mode": "free", + "pos_x": 180, + "pos_y": 180, + "size": 25, + "opacity": 0.95, + "blend_mode": "normal" + }, + { + "layer_number": 7, + "name": "circus_sticker_top_center_free", + "filename": "../media/circus.gif", + "type": "gif", + "mode": "free", + "pos_x": 60, + "pos_y": 260, + "size": 50, + "opacity": 1.0, + "blend_mode": "normal" + }, + { + "layer_number": 8, + "name": "bunny_sticker_right_mid_free", + "filename": "../media/bunny.gif", + "type": "gif", + "mode": "free", + "pos_x": 50, + "pos_y": 365, + "size": 75, + "opacity": 1.0, + "blend_mode": "normal" + }, + { + "layer_number": 9, + "name": "vhs_noise_center_free", + "filename": "../media/media.gif", + "type": "gif", + "mode": "free", + "pos_x": 175, + "pos_y": 350, + "size": 60, + "opacity": 0.3, + "blend_mode": "normal" + } + ] +} diff --git a/media/audio.wav b/media/audio.wav new file mode 100644 index 0000000..42a5be6 Binary files /dev/null and b/media/audio.wav differ diff --git a/media/bunny.gif b/media/bunny.gif new file mode 100644 index 0000000..95dbe35 Binary files /dev/null and b/media/bunny.gif differ diff --git a/media/circus.gif b/media/circus.gif new file mode 100644 index 0000000..12cf2c9 Binary files /dev/null and b/media/circus.gif differ diff --git a/media/gross.png b/media/gross.png new file mode 100644 index 0000000..11c6743 Binary files /dev/null and b/media/gross.png differ diff --git a/media/menino.mp4 b/media/menino.mp4 deleted file mode 100755 index 0e16b05..0000000 Binary files a/media/menino.mp4 and /dev/null differ diff --git a/media/reem.png b/media/reem.png new file mode 100644 index 0000000..9f22d93 Binary files /dev/null and b/media/reem.png differ diff --git a/media/screen.png b/media/screen.png new file mode 100644 index 0000000..3d00ecb Binary files /dev/null and b/media/screen.png differ diff --git a/transcription-example.json b/transcription-example.json new file mode 100644 index 0000000..ad903e8 --- /dev/null +++ b/transcription-example.json @@ -0,0 +1 @@ +[{"content": "in the new", "start": 0.002077, "end": 10.096557, "words": [{"conf": 0.793502, "end": 3.831176, "start": 0.002077, "word": "in"}, {"conf": 1.0, "end": 9.721856, "start": 3.831176, "word": "the"}, {"conf": 0.257509, "end": 10.096557, "start": 9.899999, "word": "new"}]}, {"content": "receive a very special night of the what", "start": 10.593582, "end": 13.62, "words": [{"conf": 0.880698, "end": 10.98, "start": 10.593582, "word": "receive"}, {"conf": 0.908101, "end": 11.069593, "start": 10.980199, "word": "a"}, {"conf": 0.994212, "end": 11.34, "start": 11.069593, "word": "very"}, {"conf": 0.836042, "end": 11.819474, "start": 11.34, "word": "special"}, {"conf": 0.890157, "end": 12.539867, "start": 12.3, "word": "night"}, {"conf": 0.800731, "end": 12.627985, "start": 12.54, "word": "of"}, {"conf": 0.981462, "end": 12.87, "start": 12.627985, "word": "the"}, {"conf": 0.985449, "end": 13.62, "start": 13.47, "word": "what"}]}, {"content": "part of the came from avellino in the", "start": 13.62, "end": 16.979918, "words": [{"conf": 0.999751, "end": 13.859696, "start": 13.62, "word": "part"}, {"conf": 0.999751, "end": 13.919696, "start": 13.859696, "word": "of"}, {"conf": 0.985837, "end": 15.799475, "start": 14.543549, "word": "the"}, {"conf": 0.451724, "end": 16.014001, "start": 15.84, "word": "came"}, {"conf": 0.999723, "end": 16.14, "start": 16.014001, "word": "from"}, {"conf": 0.994632, "end": 16.71, "start": 16.14, "word": "avellino"}, {"conf": 0.421944, "end": 16.918451, "start": 16.831659, "word": "in"}, {"conf": 0.927838, "end": 16.979918, "start": 16.918451, "word": "the"}]}, {"content": "village o'clock them not which the", "start": 16.980042, "end": 25.115975, "words": [{"conf": 0.999343, "end": 17.28, "start": 16.980042, "word": "village"}, {"conf": 0.518104, "end": 17.578077, "start": 17.28, "word": "o'clock"}, {"conf": 0.531982, "end": 17.7, "start": 17.581578, "word": "them"}, {"conf": 0.357179, "end": 18.15, "start": 17.76, "word": "not"}, {"conf": 0.427486, "end": 18.57, "start": 18.36, "word": "which"}, {"conf": 0.99724, "end": 25.115975, "start": 18.718674, "word": "the"}]}] \ No newline at end of file diff --git a/videobeaux/programs/lagkage.py b/videobeaux/programs/lagkage.py new file mode 100644 index 0000000..fcca850 --- /dev/null +++ b/videobeaux/programs/lagkage.py @@ -0,0 +1,284 @@ +# videobeaux/programs/lagkage.py +# +# Compose multiple visual layers (images/gifs/videos) on top of a base video +# using a single JSON layout file. +# +# GIF layers are preprocessed into finite MP4s that loop for roughly the base +# video duration, so the main overlay graph stays simple and stable. + +import json +import os +import random +import subprocess +from pathlib import Path + +from videobeaux.utils.ffmpeg_operations import run_ffmpeg_with_progress + + +def register_arguments(parser): + parser.description = ( + "Compose multiple visual layers (images/gifs/videos) on a base video " + "using a JSON layout file. All layers are sized & positioned relative " + "to the base video dimensions." + ) + parser.add_argument( + "--layout-json", + required=True, + help="Path to JSON layout describing all layers." + ) + parser.add_argument( + "--sequence-direction", + choices=["forward", "backward", "random"], + help="Override sequence_direction in the JSON (optional)." + ) + + +def _load_layout(path: Path): + with open(path, "r", encoding="utf-8") as f: + layout = json.load(f) + if "layers" not in layout or not layout["layers"]: + raise ValueError("Layout JSON must contain a non-empty 'layers' array.") + return layout + + +def _resolve_sequence(layout, override=None): + seq = override or layout.get("sequence_direction", "forward") + layers = layout["layers"] + layers_sorted = sorted(layers, key=lambda L: L.get("layer_number", 0)) + + if seq == "forward": + ordered = layers_sorted + elif seq == "backward": + ordered = list(reversed(layers_sorted)) + elif seq == "random": + ordered = layers_sorted[:] + random.shuffle(ordered) + else: + ordered = layers_sorted + + return seq, ordered + + +def _probe_base_info(path: str): + """Return (width, height, duration_seconds) for the base video.""" + cmd = [ + "ffprobe", + "-v", "error", + "-select_streams", "v:0", + "-show_entries", "stream=width,height", + "-show_entries", "format=duration", + "-of", "json", + path, + ] + proc = subprocess.run(cmd, capture_output=True, text=True) + if proc.returncode != 0: + raise RuntimeError( + f"ffprobe failed for {path} (code {proc.returncode}): {proc.stderr}" + ) + + data = json.loads(proc.stdout) + streams = data.get("streams") or [] + if not streams: + raise RuntimeError(f"No video stream found in {path}") + + s0 = streams[0] + width = int(s0.get("width", 0) or 0) + height = int(s0.get("height", 0) or 0) + if width <= 0 or height <= 0: + raise RuntimeError(f"Invalid video size from ffprobe for {path}: {width}x{height}") + + fmt = data.get("format") or {} + dur_str = fmt.get("duration") or "0" + try: + duration = float(dur_str) + except ValueError: + duration = 0.0 + + if duration <= 0: + duration = 0.0 + + return width, height, duration + + +def _place_expr(layer): + """Return (x, y) expressions for the overlay filter.""" + mode = layer.get("mode", "free") + + if mode == "free": + x = str(layer.get("pos_x", 0)) + y = str(layer.get("pos_y", 0)) + return x, y + + slot = layer.get("place", "center") + + if slot == "top_left": + return "0", "0" + if slot == "top_right": + return "W-w", "0" + if slot == "bottom_left": + return "0", "H-h" + if slot == "bottom_right": + return "W-w", "H-h" + + return "(W-w)/2", "(H-h)/2" + + +def _preprocess_gif(src: str, base_duration: float, tmp_dir: Path, idx: int) -> str: + """ + Transcode a GIF to a looping video with alpha that roughly matches + the base duration. + + IMPORTANT: + - We force even dimensions so filters/encoders don't choke. + - We use an alpha-capable codec (qtrle in a MOV container), + so transparency is preserved instead of being flattened. + """ + tmp_dir.mkdir(parents=True, exist_ok=True) + # Use .mov since qtrle is typically stored in a QuickTime container + temp_path = tmp_dir / f"lagkage_gif_{idx}.mov" + + cmd = [ + "ffmpeg", + "-hide_banner", + "-loglevel", "error", + "-ignore_loop", "0", + "-stream_loop", "-1", + "-i", src, + # Make width/height even and ensure we have RGBA (with alpha) + "-vf", "scale=trunc(iw/2)*2:trunc(ih/2)*2,format=rgba", + ] + + # If we know the base duration, trim to that; otherwise just loop and + # let the main overlay graph's base video duration cap play-out. + if base_duration > 0: + cmd += ["-t", f"{base_duration:.3f}"] + + cmd += [ + # Alpha-capable codec + "-c:v", "qtrle", + "-an", + "-y", + str(temp_path), + ] + + proc = subprocess.run(cmd) + if proc.returncode != 0: + raise RuntimeError(f"GIF preprocess failed for {src} (code {proc.returncode})") + + return str(temp_path) + + +def run(args): + layout_path = Path(args.layout_json) + if not layout_path.exists(): + raise FileNotFoundError(f"Layout JSON not found: {layout_path}") + + layout = _load_layout(layout_path) + seq, ordered_layers = _resolve_sequence(layout, args.sequence_direction) + + base_input = args.input + if not base_input: + raise ValueError("Global --input (base video) is required for json_layers.") + + # 1) Probe base video info once + base_w, base_h, base_duration = _probe_base_info(base_input) + + # 2) Prepare inputs for main ffmpeg call + # index 0: base video + # index 1..N: layer sources (with GIFs preprocessed to MP4) + inputs_for_ffmpeg = [("base", base_input)] + layer_inputs = [] # (layer_dict, input_index, target_width_px) + + # Folder to hold temp GIF->MP4 files (next to the output file) + tmp_dir = Path(args.output).with_suffix("") + + for idx, layer in enumerate(ordered_layers, start=1): + filename = layer.get("filename") + if not filename: + raise ValueError(f"Layer missing 'filename': {layer}") + + # Resolve relative to layout JSON file + if not os.path.isabs(filename): + src = str(layout_path.parent / filename) + else: + src = filename + + size_pct = float(layer.get("size", 100)) / 100.0 + target_w = max(1, int(base_w * size_pct)) + + layer_type = (layer.get("type") or "").lower() + + # If GIF, pre-process to finite-length MP4 that loops to base duration + if layer_type == "gif": + overlay_src = _preprocess_gif(src, base_duration, tmp_dir, idx) + else: + overlay_src = src + + inputs_for_ffmpeg.append(("video", overlay_src)) + layer_inputs.append((layer, len(inputs_for_ffmpeg) - 1, target_w)) + + # 3) Build filter_complex + filter_parts = [] + + # Base video label is [0:v] directly (like overlay_img_pro) + current_label = "[0:v]" + + for idx, (layer, input_index, target_w) in enumerate(layer_inputs, start=1): + lay_in = f"[{input_index}:v]" + lay_alpha = f"[lay{idx}]" + next_label = f"[tmp{idx}]" + + opacity = float(layer.get("opacity", 1.0)) + # blend_mode is kept for future use but ignored here + _blend_mode = (layer.get("blend_mode") or "normal").lower() + + x_expr, y_expr = _place_expr(layer) + + # scale + alpha + filter_parts.append( + f"{lay_in}" + f"scale={target_w}:-1," + f"format=rgba,colorchannelmixer=aa={opacity}" + f"{lay_alpha}" + ) + + # overlay + filter_parts.append( + f"{current_label}{lay_alpha}" + f"overlay=x={x_expr}:y={y_expr}:format=auto" + f"{next_label}" + ) + + current_label = next_label + + out_label = "[out_v]" + filter_parts.append(f"{current_label}format=yuv420p{out_label}") + + filter_complex = ";".join(filter_parts) + + # 4) Build main ffmpeg command + command = [ + "ffmpeg", + "-err_detect", "ignore_err", + "-fflags", "+discardcorrupt+genpts", + ] + + for _typ, src in inputs_for_ffmpeg: + command.extend(["-i", src]) + + command.extend([ + "-filter_complex", filter_complex, + "-map", out_label, + "-map", "0:a", + "-c:v", "libx264", + "-profile:v", "high", + "-level:v", "4.2", + "-pix_fmt", "yuv420p", + "-movflags", "+faststart", + "-c:a", "aac", + args.output, + ]) + + final_cmd = (command[:1] + ["-y"] + command[1:]) if args.force else command + + run_ffmpeg_with_progress(final_cmd, args.input, args.output) diff --git a/videobeaux/programs/xpiritualism.py b/videobeaux/programs/xpiritualism.py new file mode 100644 index 0000000..0d6e8ab --- /dev/null +++ b/videobeaux/programs/xpiritualism.py @@ -0,0 +1,203 @@ +# videobeaux/programs/xpiritualism.py +# +# Xpiritualism-style aesthetic: +# - Soft pastel glow +# - Multi-layer bloom +# - Hazy vignette (implemented via blend, not fragile options) +# - Gentle film grain +# - Optional hue shift +# +# Usage example: +# videobeaux -P xpiritualism -i input.mp4 -o xpiri_soft.mp4 \ +# --style soft --bloom-radius 10 --bloom-strength 0.8 \ +# --saturation 1.2 --grain 8 --vignette 0.4 + +from videobeaux.utils.ffmpeg_operations import run_ffmpeg_with_progress + + +def register_arguments(parser): + parser.description = ( + "Xpiritualism aesthetic: multi-layer bloom + pastel spiritualizer.\n" + "Layers:\n" + " - Soft bloom / glow\n" + " - Pastel color grade / hue shift\n" + " - Hazy vignette\n" + " - Film-like grain overlay\n" + "Presets via --style, with tunable intensities." + ) + + # High-level “mood” preset + parser.add_argument( + "--style", + choices=["soft", "deep", "cosmic"], + default="soft", + help=( + "Xpiritualism style preset:\n" + " soft = gentle, pastel, minimal grain (default)\n" + " deep = richer contrast, stronger vignette & bloom\n" + " cosmic = more hue shift, grainier, dreamy" + ) + ) + + # Bloom controls + parser.add_argument( + "--bloom-radius", + type=float, + default=8.0, + help="Bloom blur radius (luma_radius for boxblur). Higher = softer glow. Default: 8.0" + ) + parser.add_argument( + "--bloom-strength", + type=float, + default=0.7, + help="Bloom blend opacity (0.0–1.0). Default: 0.7" + ) + + # Color & tone + parser.add_argument( + "--saturation", + type=float, + default=1.15, + help="Overall saturation multiplier. Default: 1.15" + ) + parser.add_argument( + "--hue-shift", + type=float, + default=0.0, + help="Hue shift in DEGREES (used in ffmpeg hue filter). Default: 0.0" + ) + + # Vignette intensity (we implement this via blend, not filter options) + parser.add_argument( + "--vignette", + type=float, + default=0.35, + help="Vignette blend strength (0.0–1.0-ish). Default: 0.35" + ) + + # Grain + parser.add_argument( + "--grain", + type=float, + default=8.0, + help="Film grain strength (ffmpeg noise alls parameter). Default: 8.0" + ) + + +def run(args): + """ + Filtergraph structure: + + [0:v] format=yuv444p,split=4 [base][bloom_src][grain_src][vig_src]; + + # Bloom layer: + [bloom_src] boxblur -> eq (sat bump) -> [bloom] + [base][bloom] blend=screen -> [bloomed] + + # Pastel grade + hue shift: + [bloomed] eq (contrast/brightness/sat) + hue -> [pastel] + + # Vignette branch (no fancy options; defaults are robust): + [vig_src] vignette [vig_mask] + [pastel][vig_mask] blend=multiply:opacity=VIGNETTE -> [vigged] + + # Grain layer: + [grain_src] noise -> [grain] + + # Final composite: + [vigged][grain] blend=overlay:opacity=0.30 -> [out_v] + """ + + # Start with user-provided values + bloom_radius = float(getattr(args, "bloom_radius", 8.0)) + bloom_strength = float(getattr(args, "bloom_strength", 0.7)) + saturation = float(getattr(args, "saturation", 1.15)) + hue_shift = float(getattr(args, "hue_shift", 0.0)) + vignette = float(getattr(args, "vignette", 0.35)) + # this is a blend opacity, not a direct vignette filter param now + grain = float(getattr(args, "grain", 8.0)) + + # Adjust based on style preset + style = getattr(args, "style", "soft") + + if style == "deep": + bloom_strength *= 1.15 + saturation *= 1.10 + vignette *= 1.20 + grain *= 1.05 + elif style == "cosmic": + # if user left hue_shift at default, give it a gentle cosmic twist + if abs(hue_shift) < 0.01: + hue_shift = 18.0 # degrees + bloom_strength *= 1.10 + saturation *= 1.05 + vignette *= 1.10 + grain *= 1.30 + + # Clamp some values into sane ranges + def clamp(val, lo, hi): + return max(lo, min(hi, val)) + + bloom_strength = clamp(bloom_strength, 0.0, 1.0) + saturation = clamp(saturation, 0.5, 2.0) + vignette = clamp(vignette, 0.0, 1.0) # now used directly as blend opacity + grain = clamp(grain, 0.0, 40.0) + + # Build filtergraph + # Note: hue filter uses radians internally; we pass degrees * PI/180. + filtergraph = ( + # Prep + split into four branches + f"[0:v]format=yuv444p,split=4[base][bloom_src][grain_src][vig_src];" + + # Bloom branch + f"[bloom_src]boxblur=luma_radius={bloom_radius}:luma_power=2," + f"eq=saturation=1.20[bloom];" + + # Screen bloom over base + f"[base][bloom]blend=all_mode=screen:all_opacity={bloom_strength}[bloomed];" + + # Pastel EQ + hue shift + f"[bloomed]eq=contrast=1.02:brightness=0.02:saturation={saturation}," + f"hue=h={hue_shift}*PI/180[pastel];" + + # Vignette branch – robust: use default vignette, then multiply with pastel + f"[vig_src]vignette[vig_mask];" + f"[pastel][vig_mask]blend=all_mode=multiply:all_opacity={vignette}[vigged];" + + # Grain branch + f"[grain_src]noise=alls={int(grain)}:allf=t+u[grain];" + + # Final overlay blend + f"[vigged][grain]blend=all_mode=overlay:all_opacity=0.30[out_v]" + ) + + command = [ + "ffmpeg", + "-err_detect", "ignore_err", + "-fflags", "+genpts+discardcorrupt", + + "-i", args.input, + + "-filter_complex", filtergraph, + "-map", "[out_v]", + "-map", "0:a?", # keep audio if present + + # Video encoding + "-c:v", "libx264", + "-preset", "medium", + "-crf", "18", + "-pix_fmt", "yuv420p", + + # Audio – copy to avoid unnecessary re-encode + "-c:a", "copy", + + args.output, + ] + + # Respect global --force: inject -y right after 'ffmpeg' + final_cmd = (command[:1] + ["-y"] + command[1:]) if getattr(args, "force", False) else command + + # Uncomment this if we need to debug the exact ffmpeg command later: + # print(" ".join(f'"{c}"' if " " in c else c for c in final_cmd)) + + run_ffmpeg_with_progress(final_cmd, args.input, args.output)