@@ -454,6 +454,20 @@ function _polyAt(t, pts) {
454454 return pts [ pts . length - 1 ] . slice ( ) ;
455455}
456456
457+ // Complete a path (pen already at `a`) along the CURRENT pipe shape.
458+ // Piecewise shapes (angular/diag45) trace their exact waypoints — hard
459+ // corners — while curved shapes use the bezier. Lets every skin that used
460+ // to stroke a raw bezierCurveTo render the shape EXACTLY.
461+ function _curveTo ( ctx , cp1 , cp2 , a , b ) {
462+ const sh = _currentShape ( ) ;
463+ if ( sh === "angular" || sh === "diag45" ) {
464+ const w = _shapeWaypoints ( a , b , sh ) ;
465+ for ( let i = 1 ; i < w . length ; i ++ ) ctx . lineTo ( w [ i ] [ 0 ] , w [ i ] [ 1 ] ) ;
466+ return ;
467+ }
468+ _curveTo ( ctx , cp1 , cp2 , a , b ) ;
469+ }
470+
457471function _bezierPoints ( a , b ) {
458472 const shape = _currentShape ( ) ;
459473 if ( shape === "straight" || ( shape === "auto" && _alignedStraight ( a , b ) ) ) {
@@ -573,7 +587,7 @@ function _renderSpiderWeb(ctx, a, b /*, color */) {
573587 // core filament
574588 ctx . globalAlpha = 0.95 ; ctx . lineWidth = 2 ;
575589 ctx . beginPath ( ) ; ctx . moveTo ( a [ 0 ] , a [ 1 ] ) ;
576- ctx . bezierCurveTo ( cp1 [ 0 ] , cp1 [ 1 ] , cp2 [ 0 ] , cp2 [ 1 ] , b [ 0 ] , b [ 1 ] ) ; ctx . stroke ( ) ;
590+ _curveTo ( ctx , cp1 , cp2 , a , b ) ; ctx . stroke ( ) ;
577591 // two wavy rails
578592 ctx . lineWidth = 1.3 ; ctx . globalAlpha = 0.85 ;
579593 for ( const side of [ - 1 , 1 ] ) {
@@ -638,12 +652,12 @@ function _renderLightsaber(ctx, a, b, color, linkType) {
638652 ctx . strokeStyle = glow ; ctx . lineWidth = 8 ; ctx . globalAlpha = 0.45 ;
639653 ctx . shadowBlur = 16 ; ctx . shadowColor = glow ;
640654 ctx . beginPath ( ) ; ctx . moveTo ( a [ 0 ] , a [ 1 ] ) ;
641- ctx . bezierCurveTo ( cp1 [ 0 ] , cp1 [ 1 ] , cp2 [ 0 ] , cp2 [ 1 ] , b [ 0 ] , b [ 1 ] ) ; ctx . stroke ( ) ;
655+ _curveTo ( ctx , cp1 , cp2 , a , b ) ; ctx . stroke ( ) ;
642656 // White core
643657 ctx . globalAlpha = 1 ; ctx . shadowBlur = 0 ;
644658 ctx . strokeStyle = C . white ; ctx . lineWidth = 2 ;
645659 ctx . beginPath ( ) ; ctx . moveTo ( a [ 0 ] , a [ 1 ] ) ;
646- ctx . bezierCurveTo ( cp1 [ 0 ] , cp1 [ 1 ] , cp2 [ 0 ] , cp2 [ 1 ] , b [ 0 ] , b [ 1 ] ) ; ctx . stroke ( ) ;
660+ _curveTo ( ctx , cp1 , cp2 , a , b ) ; ctx . stroke ( ) ;
647661 ctx . restore ( ) ;
648662}
649663function _renderDnaHelix ( ctx , a , b , color ) {
@@ -681,7 +695,7 @@ function _renderRainbowFlow(ctx, a, b) {
681695 ctx . save ( ) ;
682696 ctx . strokeStyle = grad ; ctx . lineWidth = 3 ;
683697 ctx . beginPath ( ) ; ctx . moveTo ( a [ 0 ] , a [ 1 ] ) ;
684- ctx . bezierCurveTo ( cp1 [ 0 ] , cp1 [ 1 ] , cp2 [ 0 ] , cp2 [ 1 ] , b [ 0 ] , b [ 1 ] ) ; ctx . stroke ( ) ;
698+ _curveTo ( ctx , cp1 , cp2 , a , b ) ; ctx . stroke ( ) ;
685699 ctx . restore ( ) ;
686700}
687701function _renderDashedMarch ( ctx , a , b , color ) {
@@ -691,7 +705,7 @@ function _renderDashedMarch(ctx, a, b, color) {
691705 ctx . setLineDash ( [ 8 , 6 ] ) ;
692706 ctx . lineDashOffset = - ( ( performance . now ( ) / 40 ) % 14 ) ;
693707 ctx . beginPath ( ) ; ctx . moveTo ( a [ 0 ] , a [ 1 ] ) ;
694- ctx . bezierCurveTo ( cp1 [ 0 ] , cp1 [ 1 ] , cp2 [ 0 ] , cp2 [ 1 ] , b [ 0 ] , b [ 1 ] ) ; ctx . stroke ( ) ;
708+ _curveTo ( ctx , cp1 , cp2 , a , b ) ; ctx . stroke ( ) ;
695709 ctx . setLineDash ( [ ] ) ; ctx . restore ( ) ;
696710}
697711function _renderLightning ( ctx , a , b , color ) {
@@ -720,7 +734,7 @@ function _renderPulsePacket(ctx, a, b, color) {
720734 ctx . save ( ) ;
721735 ctx . strokeStyle = color ; ctx . lineWidth = 2 ; ctx . globalAlpha = 0.7 ;
722736 ctx . beginPath ( ) ; ctx . moveTo ( a [ 0 ] , a [ 1 ] ) ;
723- ctx . bezierCurveTo ( cp1 [ 0 ] , cp1 [ 1 ] , cp2 [ 0 ] , cp2 [ 1 ] , b [ 0 ] , b [ 1 ] ) ; ctx . stroke ( ) ;
737+ _curveTo ( ctx , cp1 , cp2 , a , b ) ; ctx . stroke ( ) ;
724738 ctx . globalAlpha = 1 ;
725739 const t = ( ( performance . now ( ) / 1500 ) % 1 ) ;
726740 const [ px , py ] = _bezierAt ( t , a , cp1 , cp2 , b ) ;
@@ -735,12 +749,12 @@ function _renderNeonTube(ctx, a, b, color) {
735749 ctx . strokeStyle = color ; ctx . lineWidth = 6 ; ctx . globalAlpha = 0.25 ;
736750 ctx . shadowBlur = 18 ; ctx . shadowColor = color ;
737751 ctx . beginPath ( ) ; ctx . moveTo ( a [ 0 ] , a [ 1 ] ) ;
738- ctx . bezierCurveTo ( cp1 [ 0 ] , cp1 [ 1 ] , cp2 [ 0 ] , cp2 [ 1 ] , b [ 0 ] , b [ 1 ] ) ; ctx . stroke ( ) ;
752+ _curveTo ( ctx , cp1 , cp2 , a , b ) ; ctx . stroke ( ) ;
739753 // bright thin core
740754 ctx . globalAlpha = 1 ; ctx . shadowBlur = 0 ;
741755 ctx . strokeStyle = C . white ; ctx . lineWidth = 1.5 ;
742756 ctx . beginPath ( ) ; ctx . moveTo ( a [ 0 ] , a [ 1 ] ) ;
743- ctx . bezierCurveTo ( cp1 [ 0 ] , cp1 [ 1 ] , cp2 [ 0 ] , cp2 [ 1 ] , b [ 0 ] , b [ 1 ] ) ; ctx . stroke ( ) ;
757+ _curveTo ( ctx , cp1 , cp2 , a , b ) ; ctx . stroke ( ) ;
744758 ctx . restore ( ) ;
745759}
746760
@@ -770,7 +784,7 @@ function _renderGradient(ctx, a, b, color, linkType) {
770784 ctx . save ( ) ; ctx . lineCap = "round" ; ctx . lineWidth = 3.5 ; ctx . strokeStyle = grad ;
771785 ctx . shadowBlur = 6 ; ctx . shadowColor = color ;
772786 ctx . beginPath ( ) ; ctx . moveTo ( a [ 0 ] , a [ 1 ] ) ;
773- ctx . bezierCurveTo ( cp1 [ 0 ] , cp1 [ 1 ] , cp2 [ 0 ] , cp2 [ 1 ] , b [ 0 ] , b [ 1 ] ) ; ctx . stroke ( ) ;
787+ _curveTo ( ctx , cp1 , cp2 , a , b ) ; ctx . stroke ( ) ;
774788 ctx . restore ( ) ;
775789}
776790// Flame: red→orange→yellow gradient that flickers + tapers, with ember glow.
@@ -795,7 +809,7 @@ function _renderComet(ctx, a, b, color) {
795809 ctx . save ( ) ; ctx . lineCap = "round" ;
796810 ctx . strokeStyle = color ; ctx . globalAlpha = 0.22 ; ctx . lineWidth = 2 ;
797811 ctx . beginPath ( ) ; ctx . moveTo ( a [ 0 ] , a [ 1 ] ) ;
798- ctx . bezierCurveTo ( cp1 [ 0 ] , cp1 [ 1 ] , cp2 [ 0 ] , cp2 [ 1 ] , b [ 0 ] , b [ 1 ] ) ; ctx . stroke ( ) ;
812+ _curveTo ( ctx , cp1 , cp2 , a , b ) ; ctx . stroke ( ) ;
799813 const head = ( performance . now ( ) / 900 ) % 1 , TRAIL = 14 ;
800814 for ( let i = 0 ; i < TRAIL ; i ++ ) {
801815 const t = head - i * 0.025 ; if ( t < 0 ) continue ;
@@ -812,10 +826,10 @@ function _renderCandy(ctx, a, b, color) {
812826 ctx . save ( ) ; ctx . lineCap = "butt" ; ctx . lineWidth = 4.5 ;
813827 ctx . strokeStyle = "#ffffff" ;
814828 ctx . beginPath ( ) ; ctx . moveTo ( a [ 0 ] , a [ 1 ] ) ;
815- ctx . bezierCurveTo ( cp1 [ 0 ] , cp1 [ 1 ] , cp2 [ 0 ] , cp2 [ 1 ] , b [ 0 ] , b [ 1 ] ) ; ctx . stroke ( ) ;
829+ _curveTo ( ctx , cp1 , cp2 , a , b ) ; ctx . stroke ( ) ;
816830 ctx . strokeStyle = color ; ctx . lineWidth = 4.5 ; ctx . setLineDash ( [ 8 , 8 ] ) ; ctx . lineDashOffset = - off ;
817831 ctx . beginPath ( ) ; ctx . moveTo ( a [ 0 ] , a [ 1 ] ) ;
818- ctx . bezierCurveTo ( cp1 [ 0 ] , cp1 [ 1 ] , cp2 [ 0 ] , cp2 [ 1 ] , b [ 0 ] , b [ 1 ] ) ; ctx . stroke ( ) ;
832+ _curveTo ( ctx , cp1 , cp2 , a , b ) ; ctx . stroke ( ) ;
819833 ctx . setLineDash ( [ ] ) ; ctx . restore ( ) ;
820834}
821835// Aurora: soft green↔blue↔purple ribbon that breathes along the wire.
@@ -860,7 +874,7 @@ function _renderHeartbeat(ctx, a, b, color) {
860874function _trunk ( ctx , a , cp1 , cp2 , b , color , w , glow ) {
861875 ctx . beginPath ( ) ;
862876 ctx . moveTo ( a [ 0 ] , a [ 1 ] ) ;
863- ctx . bezierCurveTo ( cp1 [ 0 ] , cp1 [ 1 ] , cp2 [ 0 ] , cp2 [ 1 ] , b [ 0 ] , b [ 1 ] ) ;
877+ _curveTo ( ctx , cp1 , cp2 , a , b ) ;
864878 if ( glow ) { ctx . shadowBlur = glow ; ctx . shadowColor = color ; }
865879 ctx . lineWidth = w ; ctx . strokeStyle = color ; ctx . stroke ( ) ;
866880 ctx . shadowBlur = 0 ;
@@ -1771,6 +1785,21 @@ function _installMenuPatch() {
17711785 has_submenu : true ,
17721786 submenu : { options : submenu } ,
17731787 } ) ;
1788+ const curShape = _currentShape ( ) ;
1789+ out . push ( {
1790+ content : "〰 Pipe Shape" ,
1791+ has_submenu : true ,
1792+ submenu : {
1793+ options : SHAPES . map ( sh => ( {
1794+ content : `${ sh === curShape ? "✓ " : " " } ${ sh } ` ,
1795+ callback : ( ) => {
1796+ _shapeCache = sh ;
1797+ try { app . ui . settings . setSettingValue ( SHAPE_SETTING_ID , sh ) ; } catch ( __c2cErr ) { __c2cReport ( "c2c_noodle_styles.shape" , __c2cErr ) ; }
1798+ this . setDirty ( true , true ) ;
1799+ } ,
1800+ } ) ) ,
1801+ } ,
1802+ } ) ;
17741803 out . push ( {
17751804 content : "— also configurable in Settings → mec.noodle.style" ,
17761805 disabled : true ,
0 commit comments