PageSourceSearch

https://handmade-movement-public-viewing.netlify.app/assets/javascripts/Pigeon.js

js handmade-movement-public-viewing.netlify.app collected 2026-10-03 10:51:17 UTC 6,880 bytes, 228 lines download raw bytes

1export class Pigeon {
2  constructor( pigeons, createPigeonCallback, removePigeonCallback, updatePigeonCallback, updateSpeakerCallback, syncReadyCallback ) {
3    this.pigeons = pigeons
4    this.pigeonsSet = new Set()
5    this.createPigeon = createPigeonCallback
6    this.removePigeon = removePigeonCallback
7    this.updatePigeon = updatePigeonCallback
8    this.updateSpeaker = updateSpeakerCallback
9    this.syncReady = syncReadyCallback
10    this.synced = false
11    this.clockDelta = 0
12    this.lastPositionSyncedTime = Date.now()
13    this.connectToServer()
14    this.position = {}
15    this.emojis = ['😄', '😃', '😀', '😊', '☺', '😉', '😍', '😘', '😚', '😗', '😙', '😜', '😝', '😛', '😳', '😁', '😔', '😌', '😒', '😞', '😣', '😢', '😂', '😭', '😪', '😥', '😰', '😅', '😓', '😩', '😫', '😨', '😱', '😠', '😡', '😤', '😖', '😆', '😋', '😷', '😎', '😴', '😵', '😲', '😟', '😦', '😧', '😈', '👿', '😮', '😬', '😐', '😕', '😯', '😶', '😇', '😏', '😑', '👲', '👳', '👮', '👷', '💂', '👶', '👦', '👧', '👨', '👩', '👴', '👵', '👱', '👼', '👸', '😺', '😸', '😻', '😽', '😼', '🙀', '😿', '😹', '😾', '👹', '👺', '🙈', '🙉', '🙊', '💀', '👽', '🐶', '🐺', '🐱', '🐭', '🐹', '🐰', '🐸', '🐯', '🐨', '🐻', '🐷', '🐽', '🐮', '🐗', '🐵', '🐒', '🐴', '🐑', '🐘', '🐼', '🐧', '🐦', '🐤', '🐥', '🐣', '🐔', '🐍', '🐢', '🐛', '🐝', '🐜', '🐞', '🐌', '🐙', '🐚', '🐠', '🐟', '🐬', '🐳', '🐋', '🐄', '🐏', '🐀', '🐃', '🐅', '🐇', '🐉', '🐎', '🐐', '🐓', '🐕', '🐖', '🐁', '🐂', '🐲', '🐡', '🐊', '🐫', '🐪', '🐆', '🐈', '🐩']
16    this.emoji = this.emojis[Math.floor( Math.random() * this.emojis.length )]
17    this.speaker = null
18    this.lastSpeech = null
19  }
20
21  connectToServer() {
22    try {
23      this.ws = new WebSocket( "wss://pigeon-room.deno.dev/pigeon/?address=handmade-movement-public-viewing" )
24
25      this.ws.addEventListener( 'message', ( e ) => {
26        const receivedMsg = JSON.parse( e.data )
27          , { to = undefined, body, type, from = undefined, timestamp } = receivedMsg
28
29        if ( type == 'init' ) {
30          this.id = body.id
31
32          //console.dir( e.data )
33
34          if ( Object.keys( body.clients ).length > 2 ) {
35            for ( const id of body.clients ) {
36              if ( id != body.id ) {
37                this.pigeons[id] = this.createPigeon( id )
38                this.pigeonsSet.add( id )
39                this.requestEmoji( id )
40                this.requestLastSpeech( id )
41              }
42            }
43            // console.log( 'there are pigeons', body.clients )
44          } else {
45            // console.log( 'the first pigeon' )
46          }
47
48          this.clockDelta = Date.now() - timestamp
49          this.broadcastEmoji()
50
51          this.synced = true
52          this.syncReady()
53
54          // console.log( this.emoji, 'clockDelta: ' + this.clockDelta )
55        }
56
57        if ( type == 'position' ) {
58          this.pigeons[from].position.set( body.x, body.y, body.z )
59        }
60
61        if ( type == 'emoji' ) {
62          //if ( this.pigeons[from].emoji != body.emoji ) {
63          this.updatePigeon( from, body.emoji )
64          //}
65        }
66
67        if ( type == 'sendYourEmoji' ) {
68          this.sendMsg( {
69            to: from,
70            type: 'emoji',
71            body: {
72              emoji: this.emoji,
73            }
74          } )
75        }
76
77        if ( type == 'sendYourLastSpeech' ) {
78          if ( this.lastSpeech ) {
79            this.sendMsg( {
80              to: from,
81              type: 'speak',
82              body: {
83                word: this.lastSpeech,
84              }
85            } )
86          }
87        }
88
89        if ( type == 'speak' ) {
90          wordBaloon.innerText = body.word
91          this.updateSpeaker( from )
92          this.speaker = from
93          // console.log( 'receive a word', from, body.word )
94        }
95
96        if ( type == 'clientOpen' ) {
97          // console.log( 'open', body.id )
98          this.pigeons[body.id] = this.createPigeon( body.id )
99          this.pigeonsSet.add( body.id )
100          this.requestEmoji( body.id )
101        }
102
103        if ( type == 'clientClose' ) {
104          this.removePigeon( body.id )
105          this.pigeonsSet.delete( body.id )
106          delete this.pigeons[body.id]
107          // console.log( 'close', body.id )
108          if ( this.speaker == body.id ) {
109            this.updateSpeaker( this.speaker )
110            this.speaker = null
111            wordBaloon.innerText = ''
112          }
113        }
114
115        if ( type == 'ping' ) {
116          if ( from === undefined ) this.pong( 'all' )
117          if ( from === 'host' ) this.pong( 'host' )
118        }
119
120        if ( type == 'pong' ) console.log( 'pong' )
121      } )
122
123      this.ws.addEventListener( 'open', ( e ) => {
124        // console.log( 'ws open' )
125      } )
126
127      this.ws.addEventListener( 'close', ( e ) => {
128        if ( this.ws.readyState != 0 ) {
129          this.connectToServer()
130        }
131      } )
132
133      this.ws.addEventListener( 'error', ( e ) => {
134        if ( this.ws.readyState != 0 ) {
135          this.connectToServer()
136        }
137      } )
138    } catch ( err ) {
139      // console.log( err, "Failed to connect to server ... exiting" )
140    }
141  }
142
143  sendMsg( _msg ) {
144    const msg = _msg
145    if ( !Array.isArray( msg.to ) ) msg.to = new Array( msg.to )
146    try {
147      const msgString = JSON.stringify( msg )
148      this.ws.send( msgString )
149    }
150    catch ( error ) {
151      return false
152    }
153  }
154
155  ping( to ) {
156    this.sendMsg( {
157      to: to,
158      type: 'ping',
159      body: ''
160    } )
161  }
162
163  pong( to ) {
164    this.sendMsg( {
165      to: to,
166      type: 'pong',
167      body: ''
168    } )
169  }
170
171  boradcastCameraPosition( x, y, z ) {
172    if ( this.position.x != x || this.position.y != y || this.position.z != z || ( Date.now() - this.lastPositionSyncedTime ) > 1000 ) {
173      this.sendMsg( {
174        to: 'others',
175        type: 'position',
176        body: {
177          x: x,
178          y: y,
179          z: z,
180        }
181      } )
182
183      this.position.x = x
184      this.position.y = y
185      this.position.z = z
186
187      this.lastPositionSyncedTime = Date.now()
188    }
189  }
190
191  requestEmoji( id ) {
192    this.sendMsg( {
193      to: id,
194      type: 'sendYourEmoji',
195      body: {}
196    } )
197  }
198
199  broadcastEmoji() {
200    this.sendMsg( {
201      to: 'others',
202      type: 'emoji',
203      body: {
204        emoji: this.emoji,
205      }
206    } )
207  }
208
209  speak( speech ) {
210    this.sendMsg( {
211      to: 'others',
212      type: 'speak',
213      body: {
214        word: speech,
215      }
216    } )
217
218    this.lastSpeech = speech
219  }
220
221  requestLastSpeech( id ) {
222    this.sendMsg( {
223      to: id,
224      type: 'sendYourLastSpeech',
225      body: {}
226    } )
227  }
228}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.