@@ -14,6 +14,10 @@ export default function Pixel2CPP() {
1414 const [ h , setH ] = useState ( 64 ) ;
1515 const [ zoom , setZoom ] = useState ( 8 ) ; // pixel size in CSS px
1616 const [ showGrid , setShowGrid ] = useState ( true ) ;
17+ const [ gridSize , setGridSize ] = useState ( 1 ) ; // Grid spacing (every N pixels)
18+ const [ gridLineWidth , setGridLineWidth ] = useState ( 1 ) ; // Grid line thickness
19+ const [ gridOpacity , setGridOpacity ] = useState ( 0.15 ) ; // Grid opacity
20+ const [ gridOffset , setGridOffset ] = useState ( { x : 0 , y : 0 } ) ; // Grid offset
1721 const [ mirrorX , setMirrorX ] = useState ( false ) ;
1822 const [ mirrorY , setMirrorY ] = useState ( false ) ;
1923 const [ tool , setTool ] = useState ( "pen" ) ; // pen | erase | fill | eyedropper
@@ -1012,6 +1016,109 @@ const GFXfont ${safeName} PROGMEM = {
10121016 < label className = "flex items-center gap-1" > < input type = "checkbox" checked = { mirrorX } onChange = { ( e ) => setMirrorX ( e . target . checked ) } /> Mirror X</ label >
10131017 < label className = "flex items-center gap-1" > < input type = "checkbox" checked = { mirrorY } onChange = { ( e ) => setMirrorY ( e . target . checked ) } /> Mirror Y</ label >
10141018 </ div >
1019+
1020+ { /* Grid customization controls */ }
1021+ { showGrid && (
1022+ < div className = "space-y-2 w-full border-t border-neutral-700 pt-2" >
1023+ < div className = "flex items-center justify-between" >
1024+ < label className = "block text-xs font-medium text-neutral-300" > Grid Settings</ label >
1025+ < button
1026+ onClick = { ( ) => {
1027+ setGridSize ( 1 ) ;
1028+ setGridLineWidth ( 1 ) ;
1029+ setGridOpacity ( 0.15 ) ;
1030+ setGridOffset ( { x : 0 , y : 0 } ) ;
1031+ } }
1032+ className = "px-2 py-1 rounded bg-neutral-800 hover:bg-neutral-700 text-xs"
1033+ title = "Reset grid settings to defaults"
1034+ >
1035+ Reset
1036+ </ button >
1037+ </ div >
1038+ < div className = "grid grid-cols-2 gap-2 text-sm" >
1039+ < label className = "flex items-center gap-1" >
1040+ Spacing
1041+ < input
1042+ type = "number"
1043+ min = { 1 }
1044+ max = { 16 }
1045+ value = { gridSize }
1046+ onChange = { ( e ) => setGridSize ( clamp ( parseInt ( e . target . value ) || 1 , 1 , 16 ) ) }
1047+ className = "w-12 bg-neutral-800 rounded px-1 py-0.5 text-xs"
1048+ title = "Grid line spacing (pixels between lines)"
1049+ />
1050+ </ label >
1051+ < div className = "flex items-center gap-1" >
1052+ < label className = "flex items-center gap-1" >
1053+ Opacity
1054+ < input
1055+ type = "range"
1056+ min = { 0.01 }
1057+ max = { 0.3 }
1058+ step = { 0.01 }
1059+ value = { gridOpacity }
1060+ onChange = { ( e ) => setGridOpacity ( parseFloat ( e . target . value ) ) }
1061+ className = "w-16"
1062+ title = "Grid line opacity"
1063+ />
1064+ </ label >
1065+ < span className = "text-xs text-neutral-400" > { ( gridOpacity * 100 ) . toFixed ( 0 ) } %</ span >
1066+ </ div >
1067+ </ div >
1068+ < div className = "grid grid-cols-2 gap-2 text-sm" >
1069+ < label className = "flex items-center gap-1" >
1070+ Offset X
1071+ < input
1072+ type = "number"
1073+ min = { - 16 }
1074+ max = { 16 }
1075+ value = { gridOffset . x }
1076+ onChange = { ( e ) => setGridOffset ( prev => ( { ...prev , x : clamp ( parseInt ( e . target . value ) || 0 , - 16 , 16 ) } ) ) }
1077+ className = "w-12 bg-neutral-800 rounded px-1 py-0.5 text-xs"
1078+ title = "Horizontal grid offset"
1079+ />
1080+ </ label >
1081+ < label className = "flex items-center gap-1" >
1082+ Offset Y
1083+ < input
1084+ type = "number"
1085+ min = { - 16 }
1086+ max = { 16 }
1087+ value = { gridOffset . y }
1088+ onChange = { ( e ) => setGridOffset ( prev => ( { ...prev , y : clamp ( parseInt ( e . target . value ) || 0 , - 16 , 16 ) } ) ) }
1089+ className = "w-12 bg-neutral-800 rounded px-1 py-0.5 text-xs"
1090+ title = "Vertical grid offset"
1091+ />
1092+ </ label >
1093+ </ div >
1094+ < div className = "flex gap-1 flex-wrap" >
1095+ < button
1096+ onClick = { ( ) => { setGridSize ( 1 ) ; setGridOpacity ( 0.15 ) ; } }
1097+ className = "px-2 py-1 rounded bg-neutral-800 hover:bg-neutral-700 text-xs"
1098+ title = "Standard 1x1 pixel grid"
1099+ >
1100+ 1x1
1101+ </ button >
1102+ < button
1103+ onClick = { ( ) => { setGridSize ( 8 ) ; setGridOpacity ( 0.25 ) ; } }
1104+ className = "px-2 py-1 rounded bg-neutral-800 hover:bg-neutral-700 text-xs"
1105+ title = "8x8 pixel grid (common for 8-bit sprites)"
1106+ >
1107+ 8x8
1108+ </ button >
1109+ < button
1110+ onClick = { ( ) => { setGridSize ( 16 ) ; setGridOpacity ( 0.3 ) ; } }
1111+ className = "px-2 py-1 rounded bg-neutral-800 hover:bg-neutral-700 text-xs"
1112+ title = "16x16 pixel grid (common for tiles)"
1113+ >
1114+ 16x16
1115+ </ button >
1116+ </ div >
1117+ < div className = "text-xs text-neutral-500" >
1118+ Tip: Use spacing > 1 to create grid sections. Offsets shift the grid position.
1119+ </ div >
1120+ </ div >
1121+ ) }
10151122 < div className = "space-y-2 w-full" >
10161123 < label className = "block text-sm font-medium" > Draw mode:</ label >
10171124 < select value = { drawMode } onChange = { ( e ) => setDrawMode ( e . target . value ) } className = "w-full bg-neutral-800 rounded px-2 py-1 text-sm" >
@@ -1083,6 +1190,10 @@ const GFXfont ${safeName} PROGMEM = {
10831190 zoom = { zoom }
10841191 pixels = { data }
10851192 showGrid = { showGrid }
1193+ gridSize = { gridSize }
1194+ gridLineWidth = { gridLineWidth }
1195+ gridOpacity = { gridOpacity }
1196+ gridOffset = { gridOffset }
10861197 cursor = { tool === "eyedropper" ? "crosshair" : "pointer" }
10871198 onPointerDown = { handleMouseDown }
10881199 onPointerMove = { handleMouseMove }
0 commit comments