return function(F,y,t)local n=y.CollectionService local j=F.canvases local M=configuration.getValues()local a=M.rowsPerCanvas*M.colsPerCanvas for F,y in ipairs(n:GetTagged(constants.Tags.SurfaceCanvas))do local n=Canvas.new()local M={}for F=1,a,1 do local j=Spot.new()j.onArtChanged=function(F,y)t.SpotChanged:FireAllClients(n.id,j.id,F,y)end y:SetAttribute(constants.Attributes.SpotIdPrefix..F,j.id)table.insert(M,j)end n:registerSpots(M)y:SetAttribute(constants.Attributes.SurfaceCanvasId,n.id)j[n.id]=n end end

return function(contexts, services, remoteEvents)
	local CollectionService = services.CollectionService

	local canvases = contexts.canvases

	-- TODO: This should be injected instead for testability purposes,
	-- handle this in another PR
	local config = configuration.getValues()

	-- Initialize all objects to keep track of canvases in the world
	local spotsPerCanvas = config.rowsPerCanvas * config.colsPerCanvas
	for _, model in ipairs(CollectionService:GetTagged(constants.Tags.SurfaceCanvas)) do
		local canvas = Canvas.new()

		-- Register spots with the canvas
		local spots = {}
		for i = 1, spotsPerCanvas do
			local spot = Spot.new()
			spot.onArtChanged = function(artId, ownerUserId)
				remoteEvents.SpotChanged:FireAllClients(canvas.id, spot.id, artId, ownerUserId)
			end

			model:SetAttribute(constants.Attributes.SpotIdPrefix .. i, spot.id)
			table.insert(spots, spot)
		end
		canvas:registerSpots(spots)

		model:SetAttribute(constants.Attributes.SurfaceCanvasId, canvas.id)
		canvases[canvas.id] = canvas
	end
end
