1
1
2
- type PixelPosition = {
2
+ type PixelInput = {
3
3
row : number ;
4
4
col : number ;
5
- normalizedX : number ; // 0 to 1 from left to right
6
- normalizedY : number ; // 0 to 1 from top to bottom
5
+ totalRows : number ;
6
+ totalCols : number ;
7
+ screenX : number ;
8
+ screenWidth : number ;
9
+ alignment : 'left' | 'right' ;
10
+ emptyRatio : number ;
11
+ colors : readonly string [ ] ;
7
12
} ;
8
13
9
14
// --------------------------------------------------------------------------------
10
15
11
- export function createPixel ( position : PixelPosition , emptyBias : string , emptyRatio : number , colors : readonly string [ ] ) : HTMLElement {
12
- const pixel = document . createElement ( 'div' ) ;
13
- pixel . className = 'pixel' ;
14
-
15
- const isEmpty = shouldPixelBeEmpty ( position , emptyBias , emptyRatio ) ;
16
-
17
- if ( isEmpty ) {
18
- pixel . classList . add ( 'pixel-empty' ) ;
19
- } else {
20
- applyPixelStyling ( pixel , colors ) ;
21
- }
22
-
23
- return pixel ;
24
- }
16
+ export function createPixelPattern ( input : PixelInput ) : string | null {
17
+ const normalizedX = input . col / ( input . totalCols - 1 ) ;
18
+ const normalizedY = input . row / ( input . totalRows - 1 ) ;
19
+ const normalizedScreenX = input . screenX / input . screenWidth ;
20
+
21
+ const isEmpty = shouldPixelBeEmpty (
22
+ normalizedX ,
23
+ normalizedScreenX ,
24
+ normalizedY ,
25
+ input . alignment ,
26
+ input . emptyRatio
27
+ ) ;
25
28
26
- export function createPosition ( row : number , col : number , gridCols : number , gridRows : number ) : PixelPosition {
27
- return {
28
- row,
29
- col,
30
- normalizedX : col / ( gridCols - 1 ) ,
31
- normalizedY : row / ( gridRows - 1 )
32
- } ;
29
+ return isEmpty ? null : getRandomColor ( input . colors ) ;
33
30
}
34
31
35
32
// --------------------------------------------------------------------------------
36
33
37
- function shouldPixelBeEmpty ( position : PixelPosition , emptyBias : string , emptyRatio : number ) : boolean {
38
- if ( emptyBias === 'right' ) {
39
- return calculateRightBiasEmpty ( position , emptyRatio ) ;
40
- } else if ( emptyBias === 'left' ) {
41
- return calculateLeftBiasEmpty ( position , emptyRatio ) ;
42
- }
43
- return false ;
44
- }
34
+ function shouldPixelBeEmpty (
35
+ _normalizedX : number , // Container position (unused, kept for future use)
36
+ normalizedScreenX : number ,
37
+ normalizedY : number ,
38
+ alignment : 'left' | 'right' ,
39
+ emptyRatio : number
40
+ ) : boolean {
41
+ const boundary = calculateBoundary ( normalizedY , emptyRatio ) ;
45
42
46
- function calculateRightBiasEmpty ( position : PixelPosition , emptyRatio : number ) : boolean {
47
- const organicBoundary = calculateOrganicBoundary ( position , emptyRatio ) ;
48
-
49
- if ( position . normalizedX > organicBoundary ) {
50
- return addGhostPixelChance ( ) ;
51
- }
52
-
53
- return calculateScatterChance ( position , organicBoundary ) ;
54
- }
55
-
56
- function calculateLeftBiasEmpty ( position : PixelPosition , emptyRatio : number ) : boolean {
57
- const organicBoundary = calculateOrganicBoundary ( position , 1 - emptyRatio ) ;
58
-
59
- if ( position . normalizedX < organicBoundary ) {
60
- return addGhostPixelChance ( ) ;
43
+ if ( alignment === 'right' ) {
44
+ return normalizedScreenX > boundary ? hasGhostPixel ( ) : hasScatterEffect ( normalizedScreenX , boundary , normalizedY ) ;
45
+ } else {
46
+ return normalizedScreenX < boundary ? hasGhostPixel ( ) : hasScatterEffect ( normalizedScreenX , boundary , normalizedY ) ;
61
47
}
62
-
63
- const distanceFromEdge = Math . abs ( position . normalizedX - organicBoundary ) ;
64
- const scatterChance = Math . pow ( 1 - distanceFromEdge / ( 1 - organicBoundary ) , 2 ) * 0.25 ;
65
- const rowVariation = Math . sin ( position . normalizedY * Math . PI * 2 ) * 0.1 ;
66
-
67
- return Math . random ( ) < ( scatterChance + rowVariation ) ;
68
48
}
69
49
70
- function calculateOrganicBoundary ( position : PixelPosition , baseRatio : number ) : number {
71
- const waveOffset = Math . sin ( position . normalizedY * Math . PI * 3 ) * 0.1 ;
50
+ function calculateBoundary ( normalizedY : number , emptyRatio : number ) : number {
51
+ const waveOffset = Math . sin ( normalizedY * Math . PI * 3 ) * 0.1 ;
72
52
const randomOffset = ( Math . random ( ) - 0.5 ) * 0.15 ;
73
- return baseRatio + waveOffset + randomOffset ;
53
+ return emptyRatio + waveOffset + randomOffset ;
74
54
}
75
55
76
- function calculateScatterChance ( position : PixelPosition , boundary : number ) : boolean {
77
- const distanceFromEdge = Math . abs ( position . normalizedX - boundary ) ;
78
- const scatterChance = Math . pow ( 1 - distanceFromEdge / boundary , 2 ) * 0.25 ;
79
- const rowVariation = Math . sin ( position . normalizedY * Math . PI * 2 ) * 0.1 ;
56
+ function hasScatterEffect ( screenX : number , boundary : number , normalizedY : number ) : boolean {
57
+ const distance = Math . abs ( screenX - boundary ) ;
58
+ const scatterChance = Math . pow ( 1 - distance / boundary , 2 ) * 0.25 ;
59
+ const rowVariation = Math . sin ( normalizedY * Math . PI * 2 ) * 0.1 ;
80
60
81
61
return Math . random ( ) < ( scatterChance + rowVariation ) ;
82
62
}
83
63
84
- function addGhostPixelChance ( ) : boolean {
64
+ function hasGhostPixel ( ) : boolean {
85
65
return Math . random ( ) >= 0.3 ;
86
66
}
87
67
88
- function applyPixelStyling ( pixel : HTMLElement , colors : readonly string [ ] ) : void {
89
- const randomColor = colors [ Math . floor ( Math . random ( ) * colors . length ) ] ;
90
- pixel . style . background = randomColor ;
68
+ function getRandomColor ( colors : readonly string [ ] ) : string {
69
+ return colors [ Math . floor ( Math . random ( ) * colors . length ) ] ;
91
70
}
0 commit comments