Open edgarogh opened 1 year ago
Have you looked into polylux package? It seems like a complete solution to your task.
I don't know how I didn't find about Polylux when Googling but that's do the job perfectly!
However, it does indeed look like Polylux suffers from the exact problem I'm describing: if you add numbered headings to your slides, their number increases on each sub-slide, when you'd expect the slide to remain the same overall (apart from the overlays).
Here's an example: https://typst.app/project/rxemPv9LmpjiDKVKTESxnb
As a workaround, you can likely store the original location in some write-once state and use it to retrieve counters with .at(loc)
, and, with that, build a custom "heading" (maybe having a real one show up only on the first slide for referencing purposes). Not a very optimal solution, though.
Truth is, it would be weird to have multiple headings with the same number, as references "wouldn't work". But I think some sort of middle ground can be found here (maybe by only pointing to the first one, for example - although that might seem arbitrary).
I'm afraid there is mo easy solution that can solve that issue via some let
or show
issues. So for complex things (that can't be solved by using polylux counters for slides and subslides) to make it viable you need to go inside polylux code.
Maybe it is worth trying to make an issue in Polylux repo, so the could decide what is the best fitting missing consistent Typst feature. It is easy to store the state for some given counters, but impossible for all automatically. Maybe we should add some exporting all the states into dicts and back, maybe something entirely else. I don't know what is the best solution there.
I realize that https://discord.com/channels/1054443721975922748/1138661247940821146 might solve this issue as well -- If content could be exported to an svg string, you can simply recall the frozen state with image.decode(svg-str)
Pasting the question for reference:
Many publishers require you to provide each figure as a separate file along with your text. With figures made in typst, this is difficult to isolate since outer scope show rules will change the behavior if drawn figures are pasted elsewhere. With the merger of https://github.com/typst/typst/pull/1729, would the mechanisms be in place to, say, let svg-str = export-svg(content)?
The cli query system can then pull those svg strings and write them to a file, if they are e.g. saved to a metadata field
I'm coming back with another use-case that I randomly stumbled upon: printing student quizzes (MCQ) with randomised answer order.
Assume that template
and question
are defined. The following code creates a 30 page PDF containing the answer sheets of a multiple-choice question exam for 30 students. All of them have almost the same content, with the exception of question answers, which are pseudo-randomly permuted to make cheating harder.
#show template.with(student-count: 30)
= Exam
#question(
"What's the first letter of the alphabet?",
right: "A",
wrong: ("B", "C"),
)
To implement template()
, you need to repeat the same content 30 times with just the PRNG seed being different. You don't want any title numbering or question numbering cascading to the following sheet. There are currently two solutions:
state
or counter
after each answer sheet. This is tedious, especially when counters and state from packages are involved.datetime.now()
may result in different values between each answer sheet.The system I describe in this issue could solve this problem very trivially.
I have posted some thoughts here: https://laurmaedje.github.io/posts/frozen-state/
I've been reading the post and pondering on it. I would like to suggest an alternative angle to approach the issue. But at best I have a rough understanding of Typst architecture and internals, so what follows may be babbling.
If I understand correctly, the problem can be illustrated like this (Excalidraw permalink):
We have defined some content that depends on some state and we instance that content at different places in the document.
To produce its output each instance of the content must look at the sequence of updates of the state in document order, from the place where it's instantiated upwards.
But this turns ambiguous to which instance we are referring during some operations when we just say "content". Worst, there may be no instance at all. We want to fix this. So far so good.
Now a tentative solution has been expressed in terms of "frozen state":
From this perspective, both are features of the content, and IMO this is where things get hand-wavy and a bit philosophical about different instances that are actually the same but not quite so.
Wouldn't it be more natural to express this at the instantiation point instead of at the definition point?
For example, regular #content
instantiations would by default mean something like #content<here>
, while you could explicitly say #content<place1>
if you wanted content to be be instantiated with the state existing at place1, or #content<place1, (state2,)>
if wanted the same but with state2 taken from place here instead.
Please note that this is not about the syntax (I don't care about it) nor about what places ultimately are (they may be simply labels, or perhaps contexts, I don't have enough knowledge to identify what's the closest underlying Typst concept, so I just called them places as well as I might have called them checkpoints).
@laurmaedje
I have posted some thoughts here: https://laurmaedje.github.io/posts/frozen-state/
http://laurmaedje.github.io/ => 404 https://laurmaedje.github.io/posts/frozen-state/ => 404
@git001 Thanks for the heads-up. I made some changes the blog's build process. That broke things apparently. I'm rolling them back now. (edit: turns out it was because my GitHub student pro membership ran out and the repo was private ...)
Context / use-case
Slideshow with "fragments" or "pauses"
I would like to create a template for PDF slideshows, with a
#fragment[]
function that allows me to hide an element at first and reveal it later on a duplicate page (like reveal.js fragments or Beamer's\pause
s).Student quizz / multiple choice question with permuted answers
Described later here (scroll).
Description
To do so, I'd need the ability to duplicate a page, freezing almost all state (including
state()
variables, heading numbering, page number, etc.), except for one "iteration variable" that tells me which copy I'm laying out currently.Essentially, I'm looking for a function that would "instantiate" a
content
at a specific location (regarding state) in a way that resolves/freezes implicit and explicit state inside it, so that any attempt to lay it out multiple times results in the same state materialization.Possible implementation 1:
freeze(content, exclude: list or state)
Here, we explicitly exclude a state variable from the freezing, so it can be used and mutated inside.
Note: if a heading is inserted between the call to
freeze
and the layouts ofbody_frozen
(L5), we would expect the numbering to be in the wrong order, which I guess would be a feature?Possible implementation 2:
clone(content, count: number, exclude: list or state)
This approach would be more "managed" and tailored to my specific case, leading to less room for weird behavior such as unordered numbering:
Another possible approach would be to provide an map-like usage:
Here, the list elements would be mapped to the body, passing their values through the
idx
state variable. The state variable could maybe have its original value stored and restored after the iteration, so that it isn't observable outside?Soundness
I must admit, I haven't thought that much about the "soundness" of such a feature, and how it would interact with all the weird "meta" Typst features (locate, query, etc.).
Last note
Maybe this idea is a bad solution to the project I have initially (XY problem). Maybe it should be restricted in other ways. Or made even more generic. Maybe my initial problem should just be a Typst builtin.