render_node_and_descendants = function(id, y, xlo, xhi, grandparent_surface_node, font)
	-- draw a parent 'id' and its children
	-- also draw an edge from grandparent to parent if provided
	-- position the root between xlo and xhi to be closer to children with fewer tracks
	local parent = Nodes[id]
	if parent.children == nil then
		parent.surface_node = add_node(xlo, y, parent, grandparent_surface_node, font)
		return
	end
	local parent_xlo = xposition(parent, xlo, xhi)
	parent.surface_node = add_node(parent_xlo, y, parent, grandparent_surface_node, font)
	local parent_height = box_height(parent.surface_node)
	local curr_boundary = xlo
	for _,child_id in ipairs(parent.children) do
		local child = Nodes[child_id]
		render_node_and_descendants(child_id, y + parent_height + 50, curr_boundary, curr_boundary + 620*child.ntracks, parent.surface_node, font)
		curr_boundary = curr_boundary + 620*child.ntracks
	end
end