[Cuis-dev] Webcam support

Juan Vuletich juan at cuis.st
Wed Jun 24 10:07:41 PDT 2026


Just pushed #flipBy:on: to the repo. The attach is my suggestion for 
CameraMorph. Please review it.

Also keep in mind that if you resize the CameraMorph stretching 
differently in x and y (changing the aspect ratio), then rotation will 
look weird, as in Cuis we assume scale is just a number.

Thanks,

On 2026-06-24 1:47 PM, Juan Vuletich via Cuis-dev wrote:
> Hi Luciano!
>
> This is so cool! Just pushed it to the Cuis repo.
>
> We need to add #outOfWorld: to Cuis. Let me take a look.
>
> One thing that is not working well is scaling and rotation. To fix it, 
> I suggest moving the mirroring of the frame to #nextFrame, for 
> instance by adding this at the end:
>
>     orientation == #natural ifTrue: [
>         displayForm := displayForm flippedBy: #horizontal ].
>
> If you agree, we'd need to keep both the original and mirrored frames 
> to avoid allocating a new Form on every frame.
>
> Thanks,
>
> On 2026-06-23 10:36 AM, Luciano Notarfrancesco via Cuis-dev wrote:
>> This package implements basic webcam support using the CameraPlugin 
>> included in the stock VM. It's just a quick port from Squeak, I 
>> didn't spend a lot of time on it... but at least it seems to work 
>> fine on MacOS. Let me know of any problems.
>>
>> To test it, you can just open a new CameraMorph, for example printing 
>> this on a workspace:
>> CameraMorph new inspect
>>
>> There's a context menu to turn it on/off, set natural/original 
>> orientation, change resolution, etc.
>>
>> If you close it before turning it off, depending on how you close it 
>> it might not stop the camera (because #delete is not always sent, how 
>> to know when a morph goes outside the world?). If this happens just 
>> run CameraMorph allOff.
>>
>> Cheers,
>> Luciano
>>
-- 
Juan Vuletich
www.cuis.st
github.com/jvuletich
researchgate.net/profile/Juan-Vuletich
independent.academia.edu/JuanVuletich
patents.justia.com/inventor/juan-manuel-vuletich
-------------- next part --------------
'From Cuis7.9 [latest update: #8016] on 24 June 2026 at 2:02:07 pm'!
!classDefinition: #CameraMorph category: #Camera!
BoxMorph subclass: #CameraMorph
	instanceVariableNames: 'cameraNumber resolution orientation cameraIsOn displayForm captureDelayMs showFPS framesSinceLastDisplay lastDisplayTime fps capturedForm '
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Camera'!

!CameraMorph methodsFor: 'drawing' stamp: 'jmv 24/Jun/2026, 4:35:54 pm (UTC)'!
drawCameraImageOn: aCanvas
	| scale offset |
	scale := 1 @ 1.
	offset := 0 @ 0.
	extent = displayForm extent ifFalse: [scale := extent / displayForm extent].
	1 @ 1 = scale
		ifTrue: [aCanvas image: displayForm at: offset]
		ifFalse:
			[| originalTransformation |
			originalTransformation := aCanvas currentTransformation.
			aCanvas geometryTransformation: (originalTransformation copy translatedBy: offset; scaledBy: scale).
			aCanvas image: displayForm at: 0 @ 0.
			aCanvas geometryTransformation: originalTransformation].! !

!CameraMorph methodsFor: 'private' stamp: 'jmv 24/Jun/2026, 4:54:23 pm (UTC)'!
initializeDisplayForm
	| displayExtent cameraExtent formExtent |
	displayExtent := self extentForResolutionName: resolution.
	cameraExtent := CameraInterface frameExtent: cameraNumber.
	cameraExtent isZero 
		ifTrue: [formExtent := displayExtent]
		ifFalse: [ | camRatio frameRatio |
			formExtent := cameraExtent.
			camRatio := cameraExtent x / cameraExtent y.
			frameRatio := displayExtent x / displayExtent y.
			camRatio ~= frameRatio ifTrue: [displayExtent := displayExtent x @ (displayExtent x * camRatio reciprocal)]].
	capturedForm := Form extent: formExtent depth: 32.
	displayForm := capturedForm.
	self morphExtent: displayExtent.! !

!CameraMorph methodsFor: 'private' stamp: 'jmv 24/Jun/2026, 4:54:53 pm (UTC)'!
nextFrame
	| frameCount |
	frameCount := CameraInterface getFrameForCamera: cameraNumber into: capturedForm bits.
	frameCount = 0 ifTrue: [self increaseCaptureDelay].
	frameCount > 2 ifTrue: [self decreaseCaptureDelay].
	framesSinceLastDisplay := framesSinceLastDisplay + frameCount.
	orientation == #natural
		ifTrue: [
			displayForm == capturedForm
				ifTrue: [ displayForm := Form extent: capturedForm extent depth: 32 ].
			capturedForm flipBy: #horizontal on: displayForm ]
		ifFalse: [ displayForm := capturedForm ].! !

!classDefinition: #CameraMorph category: #Camera!
BoxMorph subclass: #CameraMorph
	instanceVariableNames: 'cameraNumber resolution orientation cameraIsOn capturedForm displayForm captureDelayMs showFPS framesSinceLastDisplay lastDisplayTime fps'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Camera'!


More information about the Cuis-dev mailing list