This is not complete answer to this question, it's rather showcase of idea I had about generative layouts and luatex. I don't think that any of following examples is useful as is,
but maybe in can serve as basis for more interesting solutions in the future, maybe something like this.
My idea is following: we have LaTeX command that stores it's content in a box ant then add list id and dimensions to the list.
\ProvidesPackage{generativelayout}
\RequirePackage{luacode}
\luaexec{%
generators = require('generativelayout')
genboxes = {}
curr_box_id = 2222
function findFreeBox(id)
if type(tex.box[id]) == 'nil' then
return id
else
return findFreeBox(id + 1)
end
end
gen = generators.getGenerator("default")
}
\newcommand\gensavebox[1]{%
\setbox0=\hbox{\fbox{#1}}
\luaexec{%
local box = tex.box[0]
curr_box_id= findFreeBox(curr_box_id)
tex.setbox('global',curr_box_id, node.copy_list(box))
table.insert(genboxes,{width=box.width / 65536 ,height=(box.height / 65536 + box.depth / 65536),box=curr_box_id})
curr_box_id = curr_box_id + 1
}
%\box0
}
Next we have environment genlayout that selects layout algorithm and run it on list of boxes:
\newenvironment{genlayout}[1][]{%
\luaexec{%
local gen_name = "\luatexluaescapestring{#1}"
if gen_name == "" then gen_name = "default" end
gen = generators.getGenerator(gen_name)
gen:init()
}
}{%
\luaexec{%
gen:run(genboxes)
}
}
This package can be used like this:
\documentclass{article}
\usepackage{lmodern,generativelayout}
\begin{document}
\pagestyle{empty}
\begin{genlayout}[]
\gensavebox{%
Hello world
}
\gensavebox{%
\begin{tabular}{l l}
hello & world\\
second & line\\
\end{tabular}
}
\gensavebox{%
\begin{minipage}{.3\textwidth}
\begin{itemize}
\item First
\item Second
\end{itemize}
\end{minipage}
}
\gensavebox{%
little bit smaller box
}
\gensavebox{totaly small box}
\gensavebox{azsvm}
\end{genlayout}
\end{document}
Now the lua library generativelayout.lua
module(...,package.seeall)
generators = {}
empty_generator = {init = function() end, run = function() end}
function getGenerator(name)
return generators[name] or empty_generator
end
printBox = function(self,box_number)
tex.print('\\fbox{\\copy'..box_number.."}")
end
generators.default = {
init = empty_generator.init,
printer = printBox,
run = function(self,boxes)
for k, v in pairs(boxes) do
self:printer(v.box)
end
end
}
Every generator is added as object with methods run and init, which are called form genlayout environment. Generator can be selected with optional parameter of genlayout, if empty, default is selected. The output is following:

We can sort the boxes:
generators.bigToSmall = {
init = generators.default.init,
printer = printBox,
run = function(self,boxes)
table.sort(boxes,function(a, b) return a.height > b.height end)
generators.default.run(self,boxes)
end
}
You can use functions from other generators, as generators.default.run(self,boxes)

More funny example of putting boxes on random places on the page:
generators.randomize = {
width = 150,
height = 150,
init = generators.default.init,
printer = function(self,box,x,y)
tex.print("\\put(",x,",",y,"){\\copy",box,"}")
end,
run = function(self,boxes)
tex.print("\\setlength\\unitlength{1pt}")
tex.print("\\begin{picture}("..self.width..","..self.height..")")
math.randomseed( os.time() )
for k,v in pairs(boxes) do
local x = math.random(self.width - v.width)
local y = math.random(self.height - v.height)
self:printer(v.box,x,y)
end
tex.print("\\end{picture}")
end
}
Here we use trick with picture environment to place things on exact place on the page

And finally, my port of http://codeincomplete.com/posts/2011/5/7/bin_packing/ to lua:
generators.binPack = {
root = {},
init = function(self) self.root = {x=0,y=0,w=280,h=250} end,
printer = generators.randomize.printer,
fit = function(self,boxes)
local node
for _,block in ipairs(boxes) do
print("Velikost boxu",block.width,block.height)
node = self:findNode(self.root, block.width,block.height)
if node then
block.fit = self:splitNode(node, block.width, block.height)
end
end
end,
findNode = function(self,root,w,h)
if root.used then
local right = self:findNode(root.right,w,h)
if right then
return right
else
return self:findNode(root.down,w,h)
end
elseif w <= root.w and h <= root.h then
return root
else
return nil
end
end,
splitNode = function (self,node,w,h)
print("Split box: ",node.x,node.y,node.w,node.h,w,h)
node.used = true
node.down = { x= node.x, y= node.y + h, w= node.w, h= node.h - h }
node.right = { x= node.x + w, y= node.y, w= node.w - w, h= h}
return node
end,
run = function(self,boxes)
--generators.randomize.run(self,boxes)
table.sort(boxes,function(a, b) return a.height > b.height end)
tex.print("\\setlength\\unitlength{1pt}")
tex.print("\\begin{picture}("..self.root.w..","..self.root.h..")")
self:fit(boxes)
for _,v in ipairs(boxes) do
if v.fit then
x= v.fit.x
y= self.root.h-v.fit.y
self:printer(v.box,x,y)
end
end
tex.print("\\end{picture}")
end
}
I don't think the result is really nice and I think there is some error in placing boxes on their exact place, but maybe someone will like it:

\putmacro from the TeXbook. Did we have like a collection of test images somewhere which we could use? – morbusg Aug 03 '12 at 13:28