[Cuis-dev] Webcam support

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


Just pushed some updates to Morphic, essentially to support #outOfWorld:.

The attach includes the previous one I sent today, together with a 
couple of simplifications.

Now the camera should turn off correctly. Please review for integration 
into Camera.pck.st.

Cheers!

On 2026-06-24 2:07 PM, Juan Vuletich via Cuis-dev wrote:
> 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: #8020] on 24 June 2026 at 3:58:15 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, 6:37:55 pm (UTC)'!
intoWorld: aWorld

	super intoWorld: aWorld.
	cameraIsOn ifFalse: [self off].! !

!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 ].! !

!CameraMorph methodsFor: 'private' stamp: 'jmv 24/Jun/2026, 6:36:22 pm (UTC)'!
outOfWorld: aWorld

	super outOfWorld: aWorld.
	cameraIsOn ifTrue: [self off].! !

!methodRemoval: CameraMorph #delete stamp: 'jmv 24/Jun/2026, 6:57:51 pm (UTC)'!
CameraMorph removeSelector: #delete!
!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