rY*tNWt_^lk
zX?%QKUHovueapiIUYK?#+1CuP8%gFz0liE^S}3!tT^1X5hAcv}B^anJVHd?hJw!>@
zkLR04imCYgdwCT>+is{@fFCe})D$1vDI2fCnXu9=$jUXH$ySvg(6YqyE^`x+lT`kCGZMr$6
z02P^MGA#1qGUU13DBs~7GTarAs*n}ST~B>>cJ_f(+18&Zme@w}(K9Dd)$X$D<({q&
zz>Ytle*M&c`EzF)<&6@ARvNumGeNmXpZ;mKHTCF&dvWUe5vuwU!psJ1*!8|%j$4Jo
zhQ=cx3S(>~mgBb{#MTuwoTJ5B;@GgzyN$xZ49)a)GYorc(j=yQG=8s{e7p6@KAtDX
z+~MyL2(H{GcL3xKy~||HKB3-YTA-7pR;F0`QtvFa5N{oz6PddN?uH1Dpjpf_N2xL)
z)8+}*^qaKW^2lk@#01@s`1#YVR|@{B?`8hg3o$IrxU;raSX)>YaCYoQF0PTEIw|Qq
zQI+NEk>O%m26J{v09_Dt!9}+5z(6U&n6o*rr2CvP2A$OR04f`&QFQHp%9Kw0txI3=o2??GWijMPhzFCSlRzo
z*g@~;=9NYz@!hH^OmN;M*GtDd?e+71mS)H-Gjmb4V9ca78=%H-WwPbVZ{V3#r4vg}
zjg1{;`0{`l9whvWn7hr9rf(ymGP$Ha;JWWR|NMAAa|~lENEJPp`C!lZvPt4l^oNSF
z&}1Iakan}CQ2)o_UUvd8Tzk3*MMOW7Pa&Y#A5*Kwy)P?!`){qbUGuy5H`11fiTNRX
zeZ8r9=bz-zq@Dg}NHXUjJlxrTS-9W2GKFuy`0Jn1
z1;+2a$>CG?A{uOIOIwPl+4@L$?K97;;F@yXzX9Zx0pDL={&zhYXM;wW3C_9VOl92_
z%t|}S6BG8ta7)39VSvV<5faSlD%FcVI5?QxxKZZ*`$zQKRfgsNDub*mor~wV>vtnU~VPhNkOS40on=0<^y9tprF!45%Vd$m1BLpeRIYgU2
zv9$cHcSys}o$~Jj)@89t0JV#m+|GnrDYs<}ap@<3N&?H-8Gx5qT`iWTz>
zib3IW27pB;to}9vwzV$)6Q9ms3vf;zISjU#_yFEWtWA;WSNpN}%te{s9b^ob{#xKz
z)Rl5%43f0Cn1ay0)ckwUqbv{r#%5+(t9aTrVsCXKZyQ}+zhPUy9HuF5?NCd
z^Br-o9*QzN+t}Kg-tAZAW6shyAwOR_-m1Fru{a9Y{c+Qy`@vN#DXySQ3z7HVRrG&;}ONz+W*x@NLReyK1!G}5@tYSOT9WDc)Y#cS`J#tLuJzwd
zq>7T~p8ThhC!*vTe5Gcs&|N>X|9F2*RW+X1Q$JgAyw!_;gt0z~&6rWLawJ5|Djih@8kXD-xy2E*s
zH5$amAVi5${yr=7aT@j0@pDG96zU-P1ab>K=L`0A;-n-Fp9ycCo`ceJbrULoV^`YJYHVjYYcM!qPjRUqMN
zlsRv~IFZ|<)0Tj$ivRW`VQ#A9+Q#*v;o$>UC#tzAxfUSPH`Bpp2n)*h{2I_Kd$Hmc
z4;)N7$TRfRR=y!-LieHFQzD=5+dy^6JSm+xDM+PdV!iCqD&FLUYk}iHKwDur@L%z6
zUo-rAB*A2(&=w2^`C!y8D@j0P*IP7^Lh^4ho&qSeBBZnsxXahv6Gjd?U_)iiE)geR
zQF;feQ{V>vxD)ieP6wJC5*4x3*awa#R
zhc$dJF*d-qRukNynGo|_9bEY@I7LcInt6VHuI=LDl9Qg^j9tT`9b2{yBhQ%?cgr$i
zNJR}vQ8n)IfFjERZ(Tm}^hW@$bu77!kfBA
zFe)fdz4(?j;P1EnwGq~_kr9y}*iR06A*>~Ae%k$T1FR`?DKK+Dy=GGu=8qmAO0XR!
zQfA0X)=#~M&zSzxj40!HzNmo{7wy~h$X-E!G?+$#x-A--Pr6I&+UJASL!NBd`UV57
zTsTSw673Q-11n{LcX>93bMPEg#jrfH)gpf5(+rHhuTY^}epB9LK^fLc%Ll6^;qWdG
zf*~OatlY~KdpV~%mBY0sqMEP
zg`JvXyypYvN&b>?54gZbEX6u6thrVCMw25RFL2)NEVf%1bAI}CK(?l0YO@K|f}yE+R4AW-Lc^Ebg*Ei_yj0VHiey5F8D6Xc-nAJ?{|~D-hD`9&`-`zf
zJpq@1uTHCU4DF+
z0rxRAL2~+ZQRH3y#ra8t+!n1?|21YOC#QQurSddw6m063gj?4WZWX-qD2`4t=>%A#
z!$=|QGP&)Xl<{HR6qZ0ikmXwtn$
za+5ght;Xf(0q>T!#8X&>E^{0cI3&AC-UTzj*mPM-QC<21gLcc_EB%?Ec05m0P7(Q~
zD?u&a^EjCN-*=mP1^Yi9?3!Oz<==}E%9Nz)5})~M$sXfWOg75S;8Q;ztGax~<_Q>|
z|Jw5-HW2wsgc=mjbmu(HQg^YlOSrZ8Z$PghW{2C;!=uUz3yvDBO-UY}&CF`pjF`Uj+dm9)%6U~j+XXTfVsNi%`Dm8yW?ySrlSJNM5
zhE|YN2GN$K2qo|5u9pM;3PS{c|3{l`kh&eHqZRTYv@Eg+h+{?!Th!enO+RqBC9eB&
z+6?z}Ppq0M#dS1{d}5mzA3x6ay%F}6@3OV_;AoJMJh>^H*K~U1`P|N-x08jZ=?Yjq
zNxP;HqIXr5f$e{F{%L7+##D*2Lh~dShmEmPQnl>u%pgsO6rcUY>+<~7{RC3CTwCQI-QG>9I8VX8YK8^HN>Vk1GHE9QhtUrBh?|pv-QvTpk>cBSXUF^15-+sgc&!Z=j5rj{
zr$r>3)baLK*K8IH!nOSNv2-95(@mWLNijc?1w?nmfFP;_d?eHNXZNn^=Wv5B(BDBe
zi*?I3KjYc*SvJ?lFu1r@#kj0z`KB9yV`Ld3l5M7*`hE#JM$!(%^+h&%pt;F>1a!jp
zW$=a@1`AQe&A5h=PLjj~x1@z6S$7?B!-E@%3GPt~DV(o<
zn8?BKqFx*s>h{jJi(!8U#1%thttj-0^eOX%zH@iJcTXPj74=_mSGE7%m`F`qGg7>_;I7}>NphA@M4reVnRmTyY;Dpy-o%*42w`O85>@)Sb&Rna
zad|*OW8X~0okxLaM6QXQw*=BhL(q$cuqzkpQDm4l)`OLG_t2u9t@6btHd+%jnNS-s
zVP~N>P`&LHi|*49=9TRweGegAMA>kaVHN6oCg4NcbUJsMKXh@1%h
z1-%gV8{gDBgT18!#Dc0HK*P96qco1w{KK@NJbmfK@#m`>q_)+Usz9FpB|vz4)+HQO
zd)--34T7$kua5LDhMj(%+l#@F!|O^YdmD|c**p{ohmS9-`hln(tKS&T^jpeUcI@gt
z8Tw0P9QZ1tDcNQr+Q(Mrt*)wz=vu2j2xcs;$Nz&v;a_z3R%7&0#GM}Pl2`K0
zGwK%_A88*BN9tg{=!QtyA01CryVDjKRjM;aTQz-tU|F%ZzrXRx#fD$(fQOf2(QM7rpL9&%)VV~@Ohc6yv?c;NcL8VM-4GK
zh5sJgJ3{dhb`7pnJAG``XQ{|mVm=tmuF6@i@4_msK213u?DAbNX>$d+-b=fJxlfHp
zP9$*?sp0k{hmNA;&E3ITfe#q`KiGYK*u|V7WT--Lx6`|-Jkce`^M@;y2WIyI>PmX#
zu=^nx8ZI%w_}ckeOtFrn9d|wmF_=g@jhA@=tT)T3J<+8iqIJ(O`PJr^!QDX#`cp>(
zCDz59zr^yr*HuLv5P3Or)IBddd&}&8+=B{t#TI<`g-(}%baoEQ0{A_%knu3IIzyu5
zz|IybgZ7(!p0Z?j*sh{IzvPYj&Yh_pT>+2gT>4`^#M^?WK|iACF?B^nTO7bU%@n)3
z!5EtQ;o)S5!^S#Pbzc6h{9g?G!su8)HTQ1>rxmu_&EbeUK*W%&?5>s{+@a2sGIQW}
z`saD-9~jgt%rZ_QXO8E1T5<|)t=_W|{n<`?>^tg?h^$tR69Dv*o3~OS>GnP>`O1>3
z387Qf*~H>c&W&+-P-W`O4ZHY!b{GaWwEo?gl=OS9C=w|d!J#{J3=)Yg-eFpVg>q*f
zz=Hdseok2l!vbGj4EAh$7h$d>V|GVz&QzY)&%$iUVwfKt=ohX?hIal2A1c8HBl~E(
zd0^9J*;!hA{^2=))GPhQ(ZRa|8GNf3CCfeO`%U5p{KO3yWR-Vl>s#TP)$P2IZ-TM=
zOX1JTWU+NFMjn)zU!sJZ`75%PLVfD~_(YydHbXlYqhI_v&aifgbbg%v_hRMErGvoS
zdWVFLz9*34jScw7qO4`E3#4k(@jw}Zbc+z!Nl~9ct$xkz6BvRx^TlUIgMt-Z4LQn=
z0OS$2)i#mS@8be9>Q!0D85E>9riCW&u3`qud-k?6d$cc-5oE&OZ-q)ppLLr$^z|3!
z)&N
Y
- Avatar Motion Tweaker
-
-
-
-
-
-
- `;
-
- const targetElement = document.getElementById('btkUI-AvatarScaleMod-MainPage');
- if(targetElement) {
- targetElement.appendChild(contentBlock);
- } else {
- console.warn('Target element "btkUI-AvatarScaleMod-MainPage" not found!');
+ class MainContent {
+ constructor(targetId) {
+ this.element = document.createElement('div');
+ this.element.id = "AvatarScaleModContainer";
+ const targetElement = document.getElementById(targetId);
+ if (targetElement) {
+ targetElement.appendChild(this.element);
+ } else {
+ console.warn(`Target element "${targetId}" not found!`);
+ }
}
}
/* -------------------------------
- * Event Handlers & Utility Functions
+ * Generic Element Class
+ * ------------------------------- */
+ class Element {
+ constructor(tagName, parentElement) {
+ this.element = document.createElement(tagName);
+ parentElement.appendChild(this.element);
+ }
+ }
+
+ /* -------------------------------
+ * Container Object
* ------------------------------- */
- {
- const sliderContainer = document.querySelector('.avatar-scale-slider-container');
- const trackInner = document.querySelector('.avatar-scale-track-inner');
- const valueDisplay = document.querySelector('.slider-value');
+ class Container extends Element {
+ constructor(parentElement, {
+ width = '100%',
+ padding = '0em',
+ paddingTop = null,
+ paddingRight = null,
+ paddingBottom = null,
+ paddingLeft = null,
+ margin = '0em',
+ marginTop = null,
+ marginRight = null,
+ marginBottom = null,
+ marginLeft = null
+ } = {}) {
+ super('div', parentElement);
+ this.element.className = "ass-container";
+ this.element.style.width = width;
+ this.element.style.padding = padding;
+ this.element.style.margin = margin;
- const SNAP_TOLERANCE = 0.02;
- let snapPoints = [];
+ // padding values
+ if (paddingTop) this.element.style.paddingTop = paddingTop;
+ if (paddingRight) this.element.style.paddingRight = paddingRight;
+ if (paddingBottom) this.element.style.paddingBottom = paddingBottom;
+ if (paddingLeft) this.element.style.paddingLeft = paddingLeft;
- let isDragging = false;
+ // margin values
+ if (marginTop) this.element.style.marginTop = marginTop;
+ if (marginRight) this.element.style.marginRight = marginRight;
+ if (marginBottom) this.element.style.marginBottom = marginBottom;
+ if (marginLeft) this.element.style.marginLeft = marginLeft;
- sliderContainer.addEventListener('mousedown', (e) => {
- isDragging = true;
- updateTrackWidth(e.clientX);
- });
+ this.flexContainer = new Element('div', this.element);
+ this.flexContainer.element.className = "ass-flex-container";
+ }
- window.addEventListener('mousemove', (e) => {
- if (!isDragging) return;
- updateTrackWidth(e.clientX);
- });
+ appendElementToFlex(element) {
+ this.flexContainer.element.appendChild(element);
+ }
- window.addEventListener('mouseup', () => {
- isDragging = false;
- });
+ appendElement(element) {
+ this.element.appendChild(element);
+ }
+ }
- function updateTrackWidth(clientX) {
- const rect = sliderContainer.getBoundingClientRect();
+ /* -------------------------------
+ * Category (label) Class
+ * ------------------------------- */
+ class Category extends Element {
+ constructor(parentElement, text) {
+ super('span', parentElement);
+ this.element.className = "ass-category-label";
+ this.element.textContent = text;
+ }
+ }
- // Get padding values from the slider container
- const paddingLeft = parseFloat(getComputedStyle(sliderContainer).paddingLeft);
- const paddingRight = parseFloat(getComputedStyle(sliderContainer).paddingRight);
+ /* -------------------------------
+ * Circle Button Class
+ * ------------------------------- */
+ class CircleButton extends Element {
+ constructor(parentElement, text) {
+ super('button', parentElement);
+ this.element.className = "ass-circle-button";
+ this.element.textContent = text;
+ }
+ }
- // Calculate the effective width and position based on padding
+ /* -------------------------------
+ * Custom Toggle Class
+ * ------------------------------- */
+ class CustomToggle extends Element {
+ constructor(parentElement) {
+ super('div', parentElement);
+ this.element.className = "ass-custom-toggle";
+
+ this.toggleCircle = new Element('div', this.element);
+ this.toggleCircle.element.className = "ass-toggle-circle";
+ this.state = false;
+
+ this.element.addEventListener('click', () => {
+ this.toggle();
+ });
+ }
+
+ toggle() {
+ this.state = !this.state;
+ if (this.state) {
+ this.toggleCircle.element.style.left = '50%';
+ } else {
+ this.toggleCircle.element.style.left = '0';
+ }
+ }
+ }
+
+ /* -------------------------------
+ * Label Class
+ * ------------------------------- */
+ class Label extends Element {
+ constructor(parentElement, text) {
+ super('span', parentElement);
+ this.element.className = "ass-label";
+ this.element.textContent = text;
+ }
+ }
+
+ /* -------------------------------
+ * ToggleSetting Class
+ * ------------------------------- */
+ class ToggleSetting extends Element {
+ constructor(parentElement, labelText) {
+ super('div', parentElement);
+ this.element.className = "ass-toggle-setting";
+
+ const label = new Label(this.element, labelText);
+ this.toggle = new CustomToggle(this.element);
+ }
+ }
+
+ /* -------------------------------
+ * Slider Object
+ * ------------------------------- */
+ class Slider extends Element {
+ constructor(parentElement, min = 0.1, max = 5, initialValue = 1.8) {
+ super('div', parentElement);
+ this.element.className = "ass-slider-container";
+ this.min = min;
+ this.max = max;
+
+ // Value display
+ this.valueDisplay = new Element('span', this.element);
+ this.valueDisplay.element.className = "ass-slider-value";
+
+ // Slider content
+ this.sliderBase = new Element('div', this.element);
+ this.sliderBase.element.className = "ass-slider-base";
+
+ this.trackInner = new Element('div', this.sliderBase.element);
+ this.trackInner.element.className = "ass-slider-inner";
+
+ this.addEventListeners();
+
+ this.setInitialValue(initialValue);
+ }
+
+ setInitialValue(value) {
+ const percentage = (value - this.min) / (this.max - this.min);
+ this.trackInner.element.style.width = `${percentage * 100}%`;
+ this.valueDisplay.element.textContent = value.toFixed(2) + "m";
+ this.addSnapPoint(percentage);
+ }
+
+ addEventListeners() {
+ this.snapPoints = [];
+ let isDragging = false;
+
+ this.element.addEventListener('mousedown', (e) => {
+ isDragging = true;
+ this.updateTrackWidth(e.clientX);
+ });
+
+ window.addEventListener('mousemove', (e) => {
+ if (!isDragging) return;
+ this.updateTrackWidth(e.clientX);
+ });
+
+ window.addEventListener('mouseup', () => {
+ isDragging = false;
+ });
+ }
+
+ updateTrackWidth(clientX) {
+ const rect = this.element.getBoundingClientRect();
+ const paddingLeft = parseFloat(getComputedStyle(this.element).paddingLeft);
+ const paddingRight = parseFloat(getComputedStyle(this.element).paddingRight);
const effectiveWidth = rect.width - paddingLeft - paddingRight;
let x = clientX - rect.left - paddingLeft;
- // Ensure the position is within the bounds of the effective width
x = Math.min(Math.max(0, x), effectiveWidth);
- const percentage = x / effectiveWidth;
- const closestSnap = snapPoints.reduce((closest, snap) => {
+ let percentage = x / effectiveWidth;
+ const closestSnap = this.snapPoints.reduce((closest, snap) => {
return Math.abs(closest - percentage) < Math.abs(snap - percentage) ? closest : snap;
}, 1);
+ const SNAP_TOLERANCE = 0.01;
if (Math.abs(closestSnap - percentage) <= SNAP_TOLERANCE) {
x = closestSnap * effectiveWidth;
+ percentage = closestSnap;
}
- trackInner.style.width = `${x}px`;
- valueDisplay.textContent = (x / effectiveWidth * 100).toFixed(2) + "m";
+ this.trackInner.element.style.width = `${x}px`;
+
+ const value = this.min + (this.max - this.min) * percentage;
+ this.valueDisplay.element.textContent = value.toFixed(2) + "m";
+
+ engine.call("asm-AvatarHeightUpdated", value);
}
- function addSnapPoint(percentage) {
+ addSnapPoint(percentage) {
if (percentage < 0 || percentage > 1) return;
- const snap = document.createElement('div');
- snap.className = 'avatar-scale-snap-point';
- snap.style.left = `${percentage * 100}%`;
- sliderContainer.appendChild(snap);
- snapPoints.push(percentage);
+ const snap = new Element('div', this.sliderBase.element);
+ snap.element.className = 'ass-snap-point';
+ snap.element.style.left = `${percentage * 100}%`;
+ this.snapPoints.push(percentage);
}
- // To evenly space out snap points:
- function addEvenSnapPoints(count) {
+ addEvenSnapPoints(count) {
for (let i = 1; i <= count; i++) {
- addSnapPoint(i / (count + 1));
+ this.addSnapPoint(i / (count + 1));
}
}
-
- // Example usage:
- addEvenSnapPoints(5); // Adds 5 evenly spaced snap points
}
+
+ // Initialization
+ injectCSS();
+ const mainContent = new MainContent('btkUI-AvatarScaleMod-MainPage');
+ if (mainContent.element) {
+
+ const mainContainer = new Container(mainContent.element, {
+ width: '75%',
+ marginTop: '2em',
+ marginLeft: '2em',
+ marginBottom: '1em'
+ });
+
+ const slider = new Slider(mainContainer.flexContainer.element, 0.1, 3);
+ const buttonContainer = new Container(mainContainer.flexContainer.element, {
+ width: '20%',
+ marginTop: '2.5em',
+ marginLeft: '1em',
+ });
+ const circleButton1 = new CircleButton(buttonContainer.flexContainer.element, "+");
+ const circleButton2 = new CircleButton(buttonContainer.flexContainer.element, "-");
+
+ const settingsContainer = new Container(mainContent.element, {
+ width: '100%',
+ marginTop: '1em',
+ marginLeft: '1em',
+ });
+ const categoryLabel = new Category(settingsContainer.element, "Universal Scaling Settings:");
+
+ const settingsContainerInner = new Container(mainContent.element, {
+ width: '90%',
+ marginTop: '1em',
+ marginLeft: '3em',
+ });
+
+ const toggleSetting = new ToggleSetting(settingsContainerInner.element, "Universal Scaling (Mod Network)");
+ const toggleSetting2 = new ToggleSetting(settingsContainerInner.element, "Recognize Scale Gesture");
+ const toggleSetting3 = new ToggleSetting(settingsContainerInner.element, "Scale Components");
+ }
+
})();
\ No newline at end of file
diff --git a/AvatarScale/resources/nak_menu.css b/AvatarScale/resources/nak_menu.css
deleted file mode 100644
index d732c3d..0000000
--- a/AvatarScale/resources/nak_menu.css
+++ /dev/null
@@ -1,13 +0,0 @@
-.slider-container {
- margin: 10px 0;
- padding: 5px;
-}
-
-.slider-label {
- display: block;
- margin-bottom: 5px;
-}
-
-.test-slider {
- width: 100%;
-}