Just to jot this down here, while I have the thought: The method I used for the .gif animations in Why does \vspace, after section heading, sometimes jump/snap in discrete steps? was basically have a bash script call pdflatex X ammount of times, each with a new value of a parameter \mylength, and generating X output PDF files. Obviously, each time pdflatex is called, it has to re-load \documentclass, then \usepackages, etc all over again - in one word, time-consuming.

I was thinking - it would be so much better if at a certain point in a .tex document, I could write something like (pseudocode):

blah blah. 

\steplength{\mylength}{2.5pt}{20pt}{0.5pt} % pseudo
\generateParameterSequencePages{}          % pseudo

\textbf{Something here}
\textit{Something else here}

Blah blah blah....

... so when the tex engine encounters \generateParameterSequencePages; it basically "saves" the state of the current page; creates a new file, \jobname_pgY.pdf, numerated with the current page number (Y in the \jobname document); and inside this new file, it tosses the Z number of iterations (that \steplength{\mylength}{startvalue}{endvalue}{step} would specify) of \mylength in the current page, as separate pages. After its done, the engine exits (not sure if I'd want the engine going back to tex'ing the original PDF at this point or not).

So, I'd end up with a new file \jobname_pgY.pdf, with Z number of pages, showing the Z iterations of parameter \mylength and their effect on layout of pg Y in the original \jobname.pdf document. I could imagine this would happen somewhat faster, then having a bash script call pdflatex each and every time.

Is something like this possible at all with current engine(s)? Would use of synctex make a difference here? How about use of luatex?

Many thanks in advance for any suggestions,

EDIT: See also this post for a more detailed lualatex example.

2 Answers 2


Why not just generate one PDF file using a \foreach which is pretty much the technique I used in Sieve of Eratosthenes in tikz to produce the animation:

\foreach \len in {2.5, 3.0, ..., 20.0}{%
    \textbf{Something here}
    \vspace{\len pt}

    \textit{Something else here}
  • Hi @PeterGrill - sorry it took a while, but many thanks for your answer! Here I'm not really interested in generating multiple graphics on a single page - I'm interested in debugging influence of lengths (and other parameters) on the typesetting of a page; I have tried to clarify better in this post. Thanks again - cheers!
    – sdaau
    May 27, 2012 at 10:51

I'll post this here, so as not to clog the original question.

But basically, the intent behind the question is to debug influence of lengths on page typesetting... I have now looked a bit into it, and can provide a partial answer: synctex "just" establishes correspondence between source .tex and output .pdf for GUI editors - however, lualatex was already helpful in understanding things a bit better.

So, I've been looking into lua-visual-debug.lua/.sty; LuaTEX Reference Manual (luatexref-t.pdf); \AtBeginShipout from package atbegshi and the output routine and \box255. Basically, I'd like to handle cases like this:





  \section{Lorem Ipsum}



  \section{Sed commodo}



In the example above, I'd like to see the influence of diverse \mylengths on the page typesetting. The problem is that we don't exactly know which page is the second section going to end up (ok, I have typeset the file once, so I know it is going to be on page 2 - however, we don't know that a-priori). But in any case, latex would have to typeset at least once up to the \mylength part.

Now, as far as I (crudely) understand it, after this \mylength part is crossed, the tex engine will keep adding page elements, until the page is overfilled. At this point, we can utilize \AtBeginShipout to run a macro or lua script - and apparently some things can be changed there; but I'm not yet sure which things or how to change them.

In the example below, I've used lua code (whose original setup is from lua-visual-debug.lua) to basically iterate through all of the nodes in the so-called AtBeginShipoutBox. At the moment when \AtBeginShipout runs, the AtBeginShipoutBox is essentially \box256; while \box255 is nil.

This tells me that the output routine has possibly not run yet - and most likely, the pdf page is not generated yet (and the terminal log indeed shows the script output before the [1],[2]... strings that are output upon pdf page generation, I guess).

So apparently, there should be the possibility to change things - however, I try to insert a tex.print("\\mylength=20pt ") as a "hack" in the \AtBeginShipout routine - and unfortunately, there is absolutely no change in the generated PDF.

However, if there had been a change; then I could imagine the following as a solution:

  • Place a "marker" in the tex file where we want to examine (e.g. at the \setlength command in the first example in this post)
  • Run latex
  • Run \AtBeginShipout
    • Has the marker been encountered on this page? If so:
    • Save the page context (style at beginning)
    • set \mylength to first step of iteration
    • switch temporarily output to another pdf
    • have output routine run and output a single page
    • From this point on, do not return execution priority to latex!
    • Start a loop until last step of iteration
    • Retrieve page context
    • change \mylength to next step
    • have output routine run and output a single page
    • (repeat loop)

So, there are two questions here:

  • Can we change something like \mylength in something like lua code running in an \AtBeginShipout; such that latex (re-)typesets the page with the new \mylength;
  • Is it possible to retrieve something like a "page context" (the "style": fonts, skips etc at the start of the typesetting of a page), save it, and retrieve the saved version, again in something like lua code running in an \AtBeginShipout?

As far as "page context", I would consider values of, say \baselineskip and such at start of typesetting of a page (this is provided by luatex as tex.baselineskip); but also if an environment (such as list) is in effect (I'd have no idea if luatex allows for checking of that or not); presumably, for those variables that luatex provides, it shouldn't be a problem to save their values somehow. But is tex.baselineskip in \AtBeginShipout the \baselineskip at the beginning of typesetting of a given page; or the one at the end (if, say, you had a \setlength{\baselineskip}{...} in the middle of the page)?

Well, that is as far as I can get now - with my limited understanding of the process, it looks like doing something like this would be possible, though I cannot find an exact procedure. So it would be really good to know if this approach is somehow fundamentally impossible (with current versions of software, at least). Also, possibly related: Concurrently interleaving execution of Lua and TeX in LuaTeX.

Anyways, here is the above example, with added lua functions to iterate and print out a node list of a page to terminal:


%\usepackage{everyshi} % use atbegshi instead

--~ module(...,package.seeall)
--~ module("...","package.seeall")

  -- running this \AtBeginShipout will typeset "test" (with the quotes) on start of every page other than first (regularly broken paragraph continues)
  function mytest()
    tex.sprint([["test"]]) -- typesets "test" (w/ quotations)

  -- texlive/2011/texmf-dist/tex/context/base/node-ini.lua
  local function simplified(t)
    local r = { }
    for k, v in next, t do
      r[k] = string.gsub(v,"_","")
    return r

  local function table2string(t)
    local ret = ""
    for i,v in ipairs(t) do
      -- print(i,v)
      ret = ret .. "[" .. i .. "]= " .. tostring(v) .. "; "
    return ret

  function print_basic_nodedata()
    local rep = "\n"
    rep = rep .. " ## node.types: " .. table2string(node.types()) .. "\n" -- doesn't list whatsit?!
    rep = rep .. " ## node.whatsits: " .. table2string(node.whatsits()) .. "\n"
    rep = rep .. " ## tex: " .. tostring(tex) .. " / " .. table2string(tex) .. "\n" -- empty at this point
    return rep

  print(print_basic_nodedata()) -- once here, as well

  -- texlive/2011/texmf-dist/tex/context/base/node-ini.lua
  function nodes_fields(n)
    local id = n.id
    --local node_fields   = node.fields
    --local nodecodes     = node.types() -- simplified(node.types())
    --local whatsit_node  = nodecodes.whatsit -- whatsit not listed in node.types(); go explicitly
    --print(id .. " / " .. table2string(nodecodes) ..  " / " .. tostring(whatsit_node))
    local whatsit_node = 8

    if id == whatsit_node then
        return node.fields(id,n.subtype) --node_fields
        local t = node.fields(id)
        return t

  function node_field_vals(n)
    local id = n.id
    local myfields = nodes_fields(n)
    local rep = ""
    local whatsit_node = 8
    local whatsit_node_subtypes = node.whatsits()
    for k, v in next, myfields do
      if ((k>0) and not(v=="head")) then -- k=0 next; k=-1 prev; k=12 head; avoid those
        local vv = ""
        if (v == "subtype") then
          if (n.id == whatsit_node) then
            vv = " (" .. tostring(whatsit_node_subtypes[n.subtype]) .. ")"
        rep = rep .. ".[" .. k .. "/" .. v .. "]= " .. tostring(n[v]) .. vv .. "; "

    if (n.id == whatsit_node) then
      if (n.subtype == 1) then -- 1: "write"
        rep = rep .. table2string(n.data[1])

    return rep .. "\n"

  level = 0

  -- texlive/2011/texmf-dist/tex/luatex/lua-visual-debug/lua-visual-debug.lua
  function show_page_elements(parent)
    local head = parent.list
    level = level + 1
    print("") -- just a newline
    while head do
      local spacer = ""
      for i=1,level,1 do
        spacer = spacer .. " "
      print(level .. spacer .. ": " .. tostring(head) .. "/" .. head.id)
      --texio.write("term and log", "\nsomething\n" )
      -- below print is for more verbose information:
--~       print (" " .. spacer .. ": " .. node_field_vals(head) )
      if head.id == 0 or head.id == 1 then -- hbox / vbox
      head = head.next
    level = level - 1
    return true

  function start_inspect_page()
    print("Start inspect page")
    print("tex.output: " .. tex.output) -- shows "{\let \par \@@par \ifnum \outputpenalty <-\@M \@specialoutput ..."
    print("tex.box[255]: " .. tostring(tex.box[255])) -- nil here
    print("tex.box[256]: " .. tostring(tex.box[256]))
    print("tex.box[AtBeginShipoutBox]: " .. tostring(tex.box["AtBeginShipoutBox"])) -- same as 256; as it says in log file: "\AtBeginShipoutBox=\box256"
--~     print(print_basic_nodedata()) -- same as the first time
    -- perform hack
    tex.print("\\mylength=20pt ")
    -- tex.tprint({-2,\\mylength=20pt}) -- gets typeset

\AtBeginShipout {%



\section{Lorem Ipsum}
% \directlua{mytest()}

% \showbox255       % > \box255=void here
% \showbox256       % > \box256=void here



\section{Sed commodo}



EDIT: Just experimented a bit with tex.set; it seems some things can be changed in \AtBeginShipout, and still have an influence on the produced PDF, such as voffset:

-- tex.voffset = "-2cm" -- works!
-- tex.set ('global', 'voffset', '2cm') --works!
-- tex.set ('global', '\\voffset', '2cm') -- nowork
tex.set ('voffset', '-2cm') --works!

However, tex.parindent is listed on the same page in the manual, " Dimension parameters", as tex.voffset - and yet, the only way a changing effect can be seen on the PDF is with global:

--tex.set ('parindent', '2cm') -- nowork
tex.set ('global', 'parindent', '2cm') -- work

The good with this is that it shows the line-breaking of words different, which I guess "proves" that we can change stuff here - and latex will typeset with changes included. which is good news. Note that tex.baselineskip is different:

-- tex.set ('baselineskip', '2cm') -- "There should have been a lua <node> here, not an object with type string!:"
-- tex.set ('\baselineskip', '20cm') -- pass, nowork
-- tex.set ('\\baselineskip', '20cm') -- pass, nowork

... and the manual also notes: " ... The glue parameters accept and return a userdata object that represents a glue_spec node"

However, I still cannot find a way to change \mylength with tex.set, so that is still a part of the problem...

  • 1
    You should add to the question, rather than writing a non answer: this is a "questions and answers" site.
    – egreg
    May 27, 2012 at 10:59
  • Hi @egreg - I was afraid the question would get too long; and when/if the post gets a complete answer, it will sink to the bottom of the page anyways, becoming more of an addendum; so I wasn't thinking its too bad. If it still is, I'll move it upstairs - cheers!
    – sdaau
    May 27, 2012 at 11:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.