From aea670478d8d2e049be685074b67eaa6b6688593 Mon Sep 17 00:00:00 2001 From: neoapps-dev Date: Fri, 10 Apr 2026 20:09:38 +0300 Subject: [PATCH] feat: initial implementation of DEV TOOLS!! --- public/images/tools/arc.png | Bin 0 -> 21428 bytes public/images/tools/loc.png | Bin 0 -> 21608 bytes public/images/tools/pck.png | Bin 0 -> 21784 bytes src/components/views/ArcEditorView.tsx | 89 ++++++++++++++++++ src/components/views/DevtoolsView.tsx | 122 ++++++++++++++++++++----- src/components/views/PckEditorView.tsx | 89 ++++++++++++++++++ src/pages/App.tsx | 8 ++ 7 files changed, 285 insertions(+), 23 deletions(-) create mode 100644 public/images/tools/arc.png create mode 100644 public/images/tools/loc.png create mode 100644 public/images/tools/pck.png create mode 100644 src/components/views/ArcEditorView.tsx create mode 100644 src/components/views/PckEditorView.tsx diff --git a/public/images/tools/arc.png b/public/images/tools/arc.png new file mode 100644 index 0000000000000000000000000000000000000000..59aedf7935776e91df0fd005e784c38450fb5d28 GIT binary patch literal 21428 zcmeHPdu$Zd8b8JAZObiUNW`lM!*Fwprn|F`wsz)ri`yZ^2i=5%-L?#wzf zWw$8UD8v_`CO&f28WR4|f5aNF&`@bXBZgNs^#)=gHEE#Xg12x>s0||bn={*`Jbcmk zN99biyJu#kD634Vsy3^G4+@eN zbBeMS!p>wY4$=sf%uB{asUDk52!|Eb#}01qWEn;FvC9gBu3)?zN0bFCb^OT6$|`AP zy~NAxywcp9lB57N#IPwc$yii1grtup6$?$h5Ds)LJ|a!tn!?{qsP zm&?uE1Eqo@PchHuGai@6%ejg;Pocx(5?pSfu#ia|EVP$hqRVx{;=p~W=HSf7Mocp< za9kpha3;J?O%HQ!p65B2hx2$GAmK0?RZ~nlRAUaQ!>%NN4M|txrlP5gRjC-#8cZJx z`q~|d#nUybMhY#!jZ2Dg&h2zr9V3FWl$MJ(=uy(XEO9uBV^}o}kaeeJ;}Ol&jEMF# zRj0qcqyYdp7)-ZuRb67SbQ6X-e+6_Sg~?T=jjF~t<`!c^YtSV;e+8&H$LdX7DA%!Q zYI>EXMMurGXjEm!Q|Rrua*8vLw`LdQ5~KDlsvPxwsl;nKW)fxfa!QXb#lzlD30Ep+YrG zQI&8-z{f%-or)q0h1gr?;=Lh9sJN)u;VvwY9DJeI6D+TgG}U1IhJnozqFPibwF}T}$|&4L zeV{~u)^uAp=*W0=D~(BtrG!(GqFAhRg8#{9qCjtFIDDB(V_+Mr2$YS6&{J44ZKcY@ z@E@SmWx7BkW8g`*PcR(gc8LtJ!kCLG?Ql}L=-DsvV%9gde=IGr%EA%@>*ZR^8lrzN zDXJoh!4SX0Bt(M&a%0^ZSd3^gmcun53SDV2E;lDA%9sf?riH?a8EFVv=H%)dbWO$e zn%Y>PGNLM{Wm0D5F2i;V^{(vw6$slmL%am6VLXinYd9N?s=xMmabkc~*_W5dn^(H# z;r2BMEj(8d@K+^kPWHOhCE?rVe|`ADuJYE`{`txlfA^g^bC|VHKk#}*a_$y+YT%7! zo1Xk?_DOzQ=b7b$vvB7pd%SBu+ZkQ+Y5rj@%_&d76 zE(fx@QWtNTV$*>#gy2Aj41s|<2Li(cb`HHWpa(U3b`0)5 zT>ED4z^i;l%i8{*#LCuvXV0vH_km_@Aaid^WnS+3G;=g7D<;4 zEDO@%{JVzp$NMu-Q`@S(=JuU;Z|$CLJdam*Jmbr2+I;Fid$&Tg*nR%97Ia`&=W|aU z$bRcI%{TyDI(;Gx`%_GxXufROlBS1*(KJ0IF#J~k_EKyLLR-E+w|Zah(veerJuS6w zf4_g0F{yYm2^vk)&n6SzylT2&MNp+HQ3M9+YN)HBGY7(f>oe?LvS8J7&`L3m{<{SL zsrkJB$o`hvzujDGqw`zC5Pi}?@S^dBz(C^*fq_nC2@KSS5Ev$Kz&&&fp^lEuz9;T9 zURd(evlqG{%Q$i31cZ&P8+O2w6z}}#SSIRd-M#%?xYqlRou^ME>0T+YI$g-NsZXDB z5gh2UIDuipJmvZ^+P6OT?YdpAb^p`Q#@UXU?0w%Tk^bxtJWZdj9jLvd=u4z*T=(6X z<+;<3pXQG~zWn&D&80TuY3wIBj3@R()QLN$oI8Tm);+@;I*(=Uozc7-;>*BLBRpXr z8X9Urn|Af|^jIHl70k1D-TWHYKZ)+R0^n&LLfA+15CQ}BMdS8GbaST#;e;bn8{f6? z#qn7Wt2nt{06A z`e!4+0{Xm|3rWn>d&=s1#r(>^rn1`S{||=J BnLhvk literal 0 HcmV?d00001 diff --git a/public/images/tools/loc.png b/public/images/tools/loc.png new file mode 100644 index 0000000000000000000000000000000000000000..07a801d9fe26015d72410c6904ec79b42ddfd1f1 GIT binary patch literal 21608 zcmeHOe^3cN}fzQwL;+r z89ch7xRl#a$I-ko$Gvc#Gs3_g0zhTSNWd>DOvGhG9W$`4ou-T=5>e}1#$0VgvfR6d z%$H<9(iWSUvs!IrCTuw}>{&FulC)dxX_PgCvZtHvR>o>$($mSQj}eY%aLRlQQ{wsl z)Nt^~Wvo@zAVX2%aM%(~vq-X!ve7h6S?!eFZiW(OrCwCoh*?yYqdxRbJV4=OA*c$H zNNSz3)lx`x8KJ)VL;}G?&!RGg7Q~H;utCaZv1$`Tf;^Xy3x;Gr8lUGV;0FO9stS~~ zC1iuOk}4^+(x-HtxO~+B5MZx2F~$vb2?P>DDC+7b;WVZ&xuLXDS|0>d2~ebv%z@QU zLN%9bvk5Z!GGJ9nE|nzzw7J$yt4!L{EotQU$^?;@!pe#nHvkW-0+$h*&SAFN%+{<@ zn~h1cF;>T8x|CPqg_`t%{WMP)?}6nR`mI7y2j@Jvm$HQkYJbC}aP0L-w#nzJ1658&<9S#)NN zozGyW@ApVtNHgX1{ru;=|6y5x5ykp%x*yH&4F)Ij1Ex?=poQx7bGj!#3f4~@>c@V8 zL|(wKoaWswBd3`a@W!dr!c7CBcN?w+u+tlxTbEFz8a2$yAlC0M zo2dwFE1~Ki15VYI%42^^A zom!jup#tQ5DWHYu7wiDB9}yu*VAeg3idBYsXA+-v>vJ zRg_Jfe)*^~TuDTp*?DAy&MXhTzHT@f<|Y$6n9W>q+u3+LE{a6Q82>etvcL<{;%JiI zHYQi;jc7^|Om(ymnMY{Z68tpXjm01g7!c$Q*h3Hu1P&R5111Lq!!03)rcS!Yx4x@l z@b%tb_Mf(!q6O?wI}Is%62$fl8csZtr4jiD@p#2+r<7B7VWNi6<1oZwh?gYf12`6R z7-nZl+SOUndM1@Ud|G~CNzb9cP=={|?2`jSO5+1hPh1`!PVV1xQMC|T_KrV&v4igY zP1&+|ZE>6b_&A;P{`>1wl}6ykSvIuaEm=tMCI&?UUKs5oGd3=XRUiIa`L6vH^NLNMG3ISyvB+nmYp13b-u zO}nxOM_ZQn{7J9BTxi{)qc z_rkEw9=|-Aa}bthD!L-D_A++%-`O~0$FK50AD(Rw#yPe|B-jdwPH{Chm#tAEY5$5Da4{yvgMPG`&_1f`+hUS09+@^9lb$?6M3yZ4sj<8?du735i z$-hYZGfI*l`TFX^OBXLqdUo$~KVk0kJQOM9+g{ytcw0)}V;$%Fdp>-^@%w&yc>c-C zhU;7h?|wB%X2cQ(1Osxr?dIRzd}`}RO4(7dBQz(ntKs+&gC%zU(tf7*0V=2ak4x5# zjg0T^3AMHkB>#1XR9X3s!E)(e7h+5=7>_kv4jBXkCI%!dKlbx6UFf_bWyRB$-v1eyqRpWmF D*2gsZ literal 0 HcmV?d00001 diff --git a/public/images/tools/pck.png b/public/images/tools/pck.png new file mode 100644 index 0000000000000000000000000000000000000000..11148ec917773a25f22905dfb0da7be89677880a GIT binary patch literal 21784 zcmeHP4{Q_H8NZ}7C1j~m1wl5ty)fGtEZDp!7Rtf}FlhCAzl1W|37zC-P?ZhbBPzzIlK&fC`%J@?XiJU+C-aFe# zA)}P3TGBpCN#32md+&R{?|Z-ZeebLu=#6!lOH{mjgOJIotP z--SPE>dM8H)ZPys{U=<^@K<;$D60FFtYPj!xXuhMc}AtEtX%YyMs44b2lsNM+B&Vy z^90K)K@%q^UeOc{hCrI49Ocmv$2W-@?G^o!>@-|C&}*P2!D(1k>@j;nRbr#Gq%ABy z)mBr>w>9y0!BFnXp5=(LP(x7EI64{($SNCk8gRudl+kU*Kw}ZD$!VxSEz)(K6?Byn z7HPZ5V&u(c3tb8&TZy&IZZD**W@`~+E@7<2Myr`MTiD`aI`J_;dzp@~;A2<1f0Aep zuAGKOO$)IM6NyAjks^~4_A?f{-OiY;jMZuc38UI7Yh2VQtMhRkdL?dA<-<})lN6ao zm2zICS#ugdU%ey2P^xBGO`rw1F;OnWSWITrF)S$XDY;N{IDp$1ct#9}K~dIJkhP>_ zLyd~2sEx{hsXF!b7a9P7J)Tq>lj;%-rkYT-MJ>>c1SXS8tF^5mky$CKN^_VO7qx(z z^HFa?Y*kp~G$mZCD1oH8RwPxXt;MDy`tengEGQB6hZ7zU-JB*m4PZK((QGlA?X?y= zYeS}cR+sW9g5+zRRLaH{*^^S>E&``FEvp(Q^J2BzX@E|eBuQYsUc1d&V)Ge&7N5`PHQT&KyVvS778jLqW=om9 zgtwO_pLZ*KGcslJc>$g`b7tOR73@Y{w0n&uR$GbDUM6^85h|VB+`5FS__PQY7AyRK+n0J0b9e1kuI28!-y zRn051N>`|=sOhQ&B$r-*W)m*PjOzm>>^4eR*9|)Izv|`+@)A^O=B63+Vt1 zR+Ham4=}zh7nEBoJOPRLxnl@PKz#9j2&dzpQpw)JE5Q+V|LA;py3%pEPBrFL-H> zdBO6c2c8(HSxf!wT<5RymezV=kHmr>W@flwTiUrSwEO+0#eb_VSdjMuGrTLU|Cwc@ zxn%`Izkj>EzZ_z!-B+THvzOjwYxbNdDTV7c*Nz8JtOcL3<>_X9{dog2SS5|{=_t?xd*p)yZx{^X08}RAKiKXc!!;A*KK*R_j z#6!qfnBwGc>SlY_Jc{DBymQ`F`q8?BYk>HEke`2P#^H4N?LMHtq4m3Rvs!Q6+-C3I zdZoVp4?Ss3p)|7g2aZhw06e@dpudk!3HD~7>1!EkqPHCC;0EfZCxL9 zZW_M&*#XFW%SVSJH5B!t)8Y6_=Oz*XBFIPth#iMSfI19hKEyao`v@?nB|(5g{(RU3 zUcE8?d`;me@srzvkQ9f?qGNMg##adoKR$n+gRhUhUOGCKrILj~$d+W{mf6}c_%8WvNz|oe`+ZFZqMe--tR|y z-#Yi(bI#y%BoHUNk>GAqFpAX!%A8v_217gHluhq}*C3DH(Aoug^ez*etNF)|AAR`j zSXO*+@YlInJqHi&gfF^|pB>xxI5}^F2;^J798J#9BPaN3lL$OOCSL^GRK!g`Z!_nr z&WD4aUqIW-1AUj^_ciVB7c;1ZC(nnjj@6$UT7Pr&p}MVPnGqS1q*Vw7a*_t4K-OHQ z{V_Wn74GZU^WK($({=BSoH+*c_u0{SiUh&VHnP5myq&Bs>SKNirZ(ibD>BXWUF!S4 zY<=M!=I*Tt=6f^0A6~Ru)9-=&1W9(WJCMKv!$1-M48v61+qlOB z;MC~INbAn|1JU;Qj^wrn?$h8OSCfAm14xjUX>}JTtM(WNvfF`Sn7-N1k&W`td){i; Sy~2Y!QoX3gy|=RAh5rEG79$4$ literal 0 HcmV?d00001 diff --git a/src/components/views/ArcEditorView.tsx b/src/components/views/ArcEditorView.tsx new file mode 100644 index 0000000..e016f38 --- /dev/null +++ b/src/components/views/ArcEditorView.tsx @@ -0,0 +1,89 @@ +import { useState, useEffect, useRef } from "react"; +import { motion } from "framer-motion"; +import { useUI, useAudio, useConfig } from "../../context/LauncherContext"; + +export default function ArcEditorView() { + const { setActiveView } = useUI(); + const { playBackSound } = useAudio(); + const { animationsEnabled } = useConfig(); + const [focusIndex, setFocusIndex] = useState(0); + const containerRef = useRef(null); + + useEffect(() => { + const handleKeyDown = (e: KeyboardEvent) => { + if (e.key === "Escape" || e.key === "Backspace") { + playBackSound(); + setActiveView("devtools"); + return; + } + if (e.key === "Enter") { + if (focusIndex === 0) { + playBackSound(); + setActiveView("devtools"); + } + } + }; + window.addEventListener("keydown", handleKeyDown); + return () => window.removeEventListener("keydown", handleKeyDown); + }, [playBackSound, setActiveView, focusIndex]); + + useEffect(() => { + const el = containerRef.current?.querySelector(`[data-index="${focusIndex}"]`) as HTMLElement; + if (el) el.focus(); + }, [focusIndex]); + + return ( + +

+ ARC Editor +

+ +
+ +

ARC Editor Coming Soon

+

+ This tool will allow you to edit ARC files. +

+
+ + +
+ ); +} diff --git a/src/components/views/DevtoolsView.tsx b/src/components/views/DevtoolsView.tsx index 6e2f1c0..ce73030 100644 --- a/src/components/views/DevtoolsView.tsx +++ b/src/components/views/DevtoolsView.tsx @@ -1,70 +1,146 @@ import { useState, useEffect, useRef } from "react"; import { motion } from "framer-motion"; import { useUI, useAudio, useConfig } from "../../context/LauncherContext"; + +interface DevTool { + id: string; + name: string; + view: string; + comingSoon: boolean; +} + +const DEV_TOOLS: DevTool[] = [ + { id: "pck", name: "PCK Editor", view: "pck-editor", comingSoon: false }, + { id: "arc", name: "ARC Editor", view: "arc-editor", comingSoon: false }, + { id: "loc", name: "LOC Editor", view: "devtools", comingSoon: false } +]; + export default function DevtoolsView() { const { setActiveView } = useUI(); - const [backHover, setBackHover] = useState(false); - const { playPressSound } = useAudio(); - const [focusIndex] = useState(null); + const { playPressSound, playBackSound } = useAudio(); + const { animationsEnabled } = useConfig(); + const [focusIndex, setFocusIndex] = useState(0); const containerRef = useRef(null); + const BACK_BUTTON_INDEX = DEV_TOOLS.length; useEffect(() => { const handleKeyDown = (e: KeyboardEvent) => { if (e.key === "Escape" || e.key === "Backspace") { - playPressSound(); + playBackSound(); setActiveView("main"); + return; + } + + if (e.key === "ArrowRight") { + setFocusIndex((prev) => (prev >= BACK_BUTTON_INDEX ? 0 : prev + 1)); + } else if (e.key === "ArrowLeft") { + setFocusIndex((prev) => (prev <= 0 ? BACK_BUTTON_INDEX : prev - 1)); + } else if (e.key === "ArrowDown") { + if (focusIndex < BACK_BUTTON_INDEX) { + setFocusIndex(BACK_BUTTON_INDEX); + } + } else if (e.key === "ArrowUp") { + if (focusIndex === BACK_BUTTON_INDEX) { + setFocusIndex(0); + } + } else if (e.key === "Enter") { + if (focusIndex === BACK_BUTTON_INDEX) { + playBackSound(); + setActiveView("main"); + } else { + playPressSound(); + const tool = DEV_TOOLS[focusIndex]; + setActiveView(tool.view); + } } }; + window.addEventListener("keydown", handleKeyDown); return () => window.removeEventListener("keydown", handleKeyDown); - }, [playPressSound, setActiveView]); + }, [focusIndex, playPressSound, playBackSound, setActiveView, BACK_BUTTON_INDEX]); useEffect(() => { if (focusIndex !== null) { - const el = containerRef.current?.querySelector( - `[data-index="${focusIndex}"]`, - ) as HTMLElement; + const el = containerRef.current?.querySelector(`[data-index="${focusIndex}"]`) as HTMLElement; if (el) el.focus(); } }, [focusIndex]); return ( -

+

Developer Tools

- - Developer Tools coming soon... - +
+ {DEV_TOOLS.map((tool, i) => ( +
setFocusIndex(i)} + onClick={() => { + playPressSound(); + setActiveView(tool.view); + }} + className={`group flex flex-col items-center gap-3 w-40 p-4 relative transition-all cursor-pointer outline-none border-2 ${focusIndex === i ? "border-[#FFFF55] bg-white/5" : "border-transparent" + }`} + > +
+ {tool.name} + {tool.comingSoon && ( +
+ + Coming Soon + +
+ )} +
+ + {tool.name} + +
+ ))} +
+
+ ); +} diff --git a/src/pages/App.tsx b/src/pages/App.tsx index 96e86ca..c5bad86 100644 --- a/src/pages/App.tsx +++ b/src/pages/App.tsx @@ -7,6 +7,8 @@ import DevtoolsView from "../components/views/DevtoolsView"; import SkinsView from "../components/views/SkinsView"; import WorkshopView from "../components/views/WorkshopView"; import SetupView from "../components/views/SetupView"; +import PckEditorView from "../components/views/PckEditorView"; +import ArcEditorView from "../components/views/ArcEditorView"; import SkinViewer from "../components/common/SkinViewer"; import TeamModal from "../components/modals/TeamModal"; import PanoramaBackground from "../components/common/PanoramaBackground"; @@ -339,6 +341,12 @@ export default function App() { {activeView === "devtools" && ( )} + {activeView === "pck-editor" && ( + + )} + {activeView === "arc-editor" && ( + + )} {activeView === "skins" && }