the scenes

O for a Muse of fire, that would ascend
The brightest heaven of invention,
A kingdom for a stage, princes to act
And monarchs to behold the swelling scene!
Henry V

1 logical location

The scenes of the plays each resides in its own location. I call them “play sections” most of the time in the code. I’m not 100% sure why. I guess it’s because there are some play sections that are not quite like scenes (particularly prologues and epilogues, for example.) But I think it’s really just that “play section” emphasizes that a play-section is nothing more than that: a sectioning of a play, which you can easily imagine being done another way. Whereas “scenes” are scenes. You have an independent sense of what a scene is or is supposed to be like.

<route path="/plays/{play}/{section}" to="play_section" />

2 flow

There’s a discussion somewhere about the wish to preserve continuity in the representation; this remark belongs there (if anywhere). The part of that which explains why we put scenes on separate pages, belongs here.

The scenes within each act were played continuously without pause.

—Sir Sidney Lee, Shakespeare and the Modern Stage

3 changes

#play-{play} <class add="in-scene" />
#play-{play}-entryway-layer <class remove="active" />
html <class remove="not-scroll-layer" />
html <class add="scroll-layer" />

3.1 document title

For scenes, the document title should be the play’s title plus the scene.

<title><play-title /> <eval>section</eval></title>

3.2 meta description

See equivalent in play.

meta[charset="utf-8"] <after>
	<xslt name="render_scene_meta_description"
				section="{section}"
				input="/static/doc/plays/{play}.xml" />
</after>
<<get scene name>>

<xsl:param name="section" />
<xsl:template match="play">
	<xsl:variable
			name="play-title"
			select="title/@unique_title" />

	<xsl:variable name="scene-name">
		<xsl:call-template name="get-scene-name">
			<xsl:with-param name="section-key" select="$section" />
		</xsl:call-template>
	</xsl:variable>

	<meta
			name="description"
			content="Text of {$scene-name} ({$section}) of Shakespeare's play {$play-title}, with marginal notes, annotations, illustrations, and audio recordings." />
</xsl:template>

4 material / container

// variables used by both scene text and stage

@import play                                    // for play background color
@import paper                                   // for paper color

// An invariant... (unless the display itself is narrower, in which case we must
// go into a different mode.)
$sceneTextWidth = 30rem
$sceneTextMargin = 2rem

$sceneTextBackgroundColor = $playBackgroundColor

Rename this element. It’s now only used for the unbounded (i.e. flow-positioned, i.e. scrollable) document content of plays (i.e. scenes, but could apply to, e.g. a role page). It’s in the body/main scrolling container.

@import play // because of play background color
@import scene
@import transition-timings
.play
	position relative
	z-index $playSheetsLayer + 1

	<<the play styles>>

The play document is waiting stage right until summoned.

transform translateX(100vw)

When it hears its cue (that is, a scene is opened), the play document comes into view.

&.in-scene
	transform translateX(0)

default-transition('transform')

So the idea is that the text is “off to the right,” and it slides into view when a scene is open. A scene must always be open when we’re looking at this. Now, some scenes may happen to be shorter than the screen. But this element will always extend at least to the top and bottom of the screen, showing the “material” on which the scene text is written.

min-height 100vh
min-height 101vh // this was for iOS hacking, but I think it's not working
background $playBackgroundColor
box-shadow 0 0 1em #111

Why? Because we want to present the text as a continuous column. There may be moments during scene transitions when the new text hasn’t loaded yet, and since the content of this element governs its height, we don’t want it to suddenly drop down to nothing. That would be ugly and jarring.

As a refinement to that, we could say that the play itself is semi-transparent where a scene is not present, showing the solid color only where one is:

background rgba($playBackgroundColor, .8)
//.scene-text
.scene-heading
.scene
	background $playBackgroundColor

This would perhaps be less confusing where the scene is shorter than the screen, but would also give a less stark blankness during the moment when scene text is loading.

The width of the scene text is specified where it can be used elsewhere. We don’t apply the padding here because some elements in the document (e.g. the header) may not want it.

width $sceneTextWidth + 2 * $sceneTextMargin

Center the sheet horizontally (within its container, which is flush horizontally to the viewport). This ensures that the scene text never goes out of view, while space is distributed evently to marginal content.

margin-left auto
margin-right auto

…except that if we totally run out of space, we make it fit, because we never allow it to clip.

To make the transition between scenes smoother, the scene text fades in and out.

DISABLED: this is not necessarily problematic, but it causes an extra paint of the scene text at the end of the transition, probably as the .scene is merged back into the parent layer (the animation being done).

UPDATE: I don’t know know if that’s true or not anymore.

@import transition-timings
.scene
	animation fade-text $defaultTransitionDuration $defaultTransitionTiming

@keyframes fade-text
	from
		opacity 0
	to
		opacity 1

5 add scene text

#scene-text <append>

<xslt name="render_play_heading_if_first_scene"
			section="{section}"
			input="/static/doc/plays/{play}.xml" />

<header class="scene-nav">
	<scene-link say="back to" to="previous" />
	<scene-link say="skip to" to="next"/>
</header>

<xslt name="render_scene_heading"
			play="{play}"
			section="{section}"
			input="/static/doc/plays/{play}.xml" />

<xslt name="render_scene_text"
			play-key="{play}"
			section-key="{section}"
      input="/static/doc/plays/text/{play}-{section}.xml" />

<div class="scene-bottom">
<xslt name="render_scene_heading"
			play="{play}"
			section="{section}"
			input="/static/doc/plays/{play}.xml" />
</div>

<footer class="scene-nav">
	<scene-link to="previous"/>
	<scene-link say="on to" to="next"/>
</footer>

</append>

5.1 getting out of a scene

I find that when I’m in a scene, I tend to want to get back to the main play sheet by touching it. So when a scene is open, a “screen” sits in front of the main sheet. It’s just a link back to the main sheet.

The element itself was added in the plays, and I’m leaving it there just to avoid an extra DOM operation.

@import docking
.play-sheet-screen
	hug-parent()
	pointer-events none
	.in-scene &
		pointer-events auto

The use of pointer-events instead of, say display, depends on the fact that the link is completely invisible (not to mention support for pointer-events). It’s motivated by the wish to minimize layout changes during transitions.

For that to work, you have to let the screen (or some container of it) know that a scene is open.

#play-{play}-choices <class add="in-scene" />

Of course, this isn’t discoverable, either.

6 next and previous scene links

Belongs under flow?

You’ll notice that there are “next” and “previous” links at the beginning and end of the scene text. I call these “proximate” scene links because if this whole web thing doesn’t work out, maybe I can get a job at the state department.

6.1 scene links

Here’s a little macro that we use above to create the scene link calls.

<xsl:template match="scene-link">
	<xslt name="render-play-section-link"
				input="/static/doc/plays/{{play}}.xml"
				relation="{@to}" prefix="{@say}"
				section-key="{{section}}" />
</xsl:template>

And here’s the transform that renders them. Remember, we can’t know the key of the next or previous scene without opening the play document (or an index of it).

<xsl:param name="section-key" />
<xsl:param name="relation" />
<xsl:param name="prefix" select="$relation" />

<xsl:variable name="play-key" select="/play/@key"/>

<xsl:template match="/play">
    <xsl:variable name="section" select="sections/section[@key=$section-key]"/>

    <xsl:choose>
	<xsl:when test="$relation='previous'">
	    <xsl:apply-templates mode="section-link" select="$section/preceding-sibling::section[1]" />
	</xsl:when>
	<xsl:when test="$relation='next'">
	    <xsl:apply-templates mode="section-link" select="$section/following-sibling::section[1]" />
	</xsl:when>
    </xsl:choose>

</xsl:template>

<xsl:template mode="section-link" match="section">
  <a href="/plays/{$play-key}/{@key}#top-of-scene"
     class="{$relation} proximate-scene-link">
    <span class="text">
      <span class="prefix">
	<xsl:value-of select="$prefix"/>
      </span>
			<xsl:text> </xsl:text>
      <xsl:value-of select="@key"/>
    </span>
  </a>
</xsl:template>

Each scene has a header and footer for navigational links to the adjacent scenes.

@import thumb-metrics
$scale = 1.5
$size = $thumbRems * $scale
.scene-nav .proximate-scene-link
	display block
	position relative

This would require that the links end up in the same place when you get to the next one, which doesn’t quite make sense for the bottom one. It might make more sense if they are in-page links that go to the top or bottom.

The links are signs that point up or down. They are both included in both places so that they can be used in succession to skip in one direction through a number of scenes.

@import signs
@import arrows
@import centering
@import paper
@import colors
@import pointing

.proximate-scene-link
	text-align center
	sign-text-color()
	height $size * .6
	overflow hidden

	&:before
		content ''
		width $size
		height @width
		background $worksColor
		position absolute
		left 50%
		transform-origin center
		transform translateX(-50%) rotate(45deg)
		box-shadow 0 0 1em -.5em #111

	&.previous:before
		top 50%
	&.next:before
		bottom 50%

	header &.previous
	footer &.next
		font-size $scale * 100%

	header &.next
	footer &.previous
		display none

	+user_pointing_at()
		background rgba(black, .1)
		&:before
			background $contextColor

In the scene text, the proximate scene links support linear navigation through the plays. They should look like signs and not completely block the “paper” behind it, in order that the scene might look continuous. The “previous” scene link in particular serves to signify that the page is part of a series, for visitors arriving at the scene from a direct external link. The “next” scene link also serves as a call to action when reaching the end of a scene by scrolling.

The proximate scene links in the scene text are large, but still secondary to the current scene.

> .text
	line-height 1
	font-weight 200
	horizontally-center()
	.prefix
		display block
		font-size 50%
		font-weight bold

&.previous > .text
	top 50%
	margin-top .2em

&.previous > .text
	bottom 50%
	margin-bottom -.2em

7 headings

7.1 play heading at the beginning

<xsl:param name="section" />
<xsl:template match="/play">
	<xsl:variable name="play" select="@key" />
	<xsl:if test="sections/section[1]/@key = $section">
		<h1 class="play-heading">
			<a class="play-heading-link" href="/plays/{$play}">
				<i>
					<xsl:value-of select="title" />
				</i>
			</a>
		</h1>
	</xsl:if>
</xsl:template>
@import exit-links
@import fonts
@import paper
@import scene
@import typesetting

.play-heading                                   // the h1 inside play header
	book-font()
	margin 0                                        // beat h1 or h2 default
	white-space pre-line

	// This bubbles to the container, meaning you get some space between the
	// scene material and the top of the viewport.  This only applies on the
	// first scene; otherwise the scene is always flush to the top.
	margin-top 1em
	padding-top .5em

	font-weight normal                      // beat h1 or h2 default default
	letter-spacing -.046em

	color #222
	background $paperColor


.play-heading                                   // the h1 inside play header
	font-size 300%                          // beat h1 default

.play-heading-link
	display block
	paper-font()
	text-align center
	padding 0 $sceneTextMargin      // so it will match other text

	> i
		font-style normal               // beat i default

7.2 scene heading every time

The “choices” anchor isn’t working here.

<xsl:param name="play" />
<xsl:param name="section" />

<<get scene name>>

<xsl:template match="/">
	<h1 class="scene-heading">
		<a href="/plays/{$play}#back-to-{$play}-choices" class="scene-play-link">
			<span class="scene-play-link-hint"></span>
			<xsl:value-of select="/play/title/@unique_title" />
			<xsl:if test="$section != (//section)[1]/@key">
				<xsl:text> </xsl:text>
				<br/>
			</xsl:if>
		</a>
		<span class="tty"> </span>
		<a href="/plays/{$play}/{$section}#top-of-scene"
			 class="scene-heading-link">
			<xsl:call-template name="get-scene-name">
				<xsl:with-param name="section-key" select="$section" />
			</xsl:call-template>
		</a>
	</h1>
</xsl:template>
.scene-heading
	has-exit-link()
	text-align center
	paper-font()
	font-size 200%                          // beat h1 default
	font-weight normal // beat h1 default
	margin 0                                // beat h1 default
	z-index 1
.scene-heading-link
	display block
	padding-top .25em
	padding-bottom .5em
	.scene-bottom &
		display none

The heading first contains the title of the play, which serves as a link back to the play’s main page—basically closing the scene text. Since the scene text appears “from the right,” dismissing it can then be thought of as a leftward move. A dedicated element is used for that.

@import colors
@import pointing
@import centering
@import arrows
@import signs
@import paper

.scene-play-link
	display block
	position relative
	z-index 2
	background $worksColor
	box-shadow 0 0 1em -.5em #111
	color $signTextColor
	color rgba(white, .6)
	+arrow-before-pointing(left, size: 1rem, color: $signTextColor)
		position absolute
		left 0
		vertically-center()
	+user_pointing_at()
		background $contextColor

So…. this is to “paper over” the shadow that’s put on .scene so that the anchor and resource lanes look like they’re behind the scene. The “proper” fix would be to make these elements actually behind the element that makes the shadow, but that raises other problems.

.scene-heading
	@require docking
	background inherit
	&:after
		content ''
		dock-bottom()
		height .75em
		margin-bottom (@height / -2)
		background inherit
		z-index 1
.scene-bottom .scene-heading:after
	display none

8 scene names

Most of the time, willshake refers to scenes by their short identifiers, which are mostly numeric. For example, the last scene of Hamlet is 5.2. Having short, canonical identifiers for the scenes is absolutely crucial to the way that willshake works. And for people who are familiar with that convention, it’s the most efficient way to communicate a location.

But these short names are not self-documenting. The longer, more familiar format, like “Act 5, Scene 2,” communicates what it is. It’s not just a scene reference, but it carries the “metadata” (in the form of the words “act” and “scene”) that tell you what it is. This is friendlier. So in places where space permits, the longer form is used.

<xsl:template name="get-scene-name">
	<xsl:param name="section" select="$section" />

	<xsl:variable name="act" select="substring-before(concat($section, '.'), '.')"/>
	<xsl:variable name="scene" select="substring-after($section, '.')"/>

	<xsl:if test="number($act) > 0">Act </xsl:if>
	<xsl:value-of select="$act" />

	<xsl:choose>
		<xsl:when test="number($scene) > 0">
			<xsl:value-of select="concat(', Scene ', $scene)"/>
		</xsl:when>
		<xsl:when test="$scene">
			<xsl:value-of select="concat(', ', $scene)" />
		</xsl:when>
	</xsl:choose>
</xsl:template>

This template is used by a couple of placeholders. Why is it duplicated in those transforms, rather than imported by them? Because it turns out that I can’t rely on xsl:import on the client. Just another harbinger of the need that I’ll have to drop client-side XSLT (which will mean dropping XSLT altogether). In the meantime, I’m just avoiding imports.1

9 composition

The scene text is composed of several elements. To make dealing with it more tractable, these elements are handled separately (to the extent possible).

Merge this into typesetting the plays.

This is where we turn our play document into HTML markup.

: $(TRANSFORMS)/render_scene_text.list/* \
|> ^o bundle scene rendering transforms ^ \
echo "<?xml version='1.0' encoding='utf-8'?>" > %o ; \
echo "<xsl:transform version='1.0'" >> %o; \
echo " xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>" >> %o; \
echo "<xsl:output omit-xml-declaration='yes' />" >> %o; \
list=`echo %f | tr ' ' '\n' | sort`; \
cat $list >> %o; \
echo "</xsl:transform>" >> %o; \
|> $(TRANSFORMS)/render_scene_text.xsl

The principal mode in this transform is “scene”.

The input to this transform is a standalone play section document.

<xsl:param name="section-key" />

<!-- Maybe the section documents should have this -->
<xsl:param name="play-key" select="/*/@play"/>

<xsl:template match="/">
  <xsl:apply-templates
			mode="scene"
			select="(//section[@key = $section-key])[1]"/>
</xsl:template>

<!-- Don't render scene location -->
<xsl:template mode="scene" match="location" />

<<scene-template>>

9.1 scene

We only render one scene at a time.

<xsl:template mode="scene" match="section">
  <div data-scene="{$play-key}-{$section-key}" class="scene">
    <xsl:apply-templates mode="scene" />
  </div>
</xsl:template>

9.2 finis

Most of the original texts end with the word “FINIS.” Not to waste any paper, the editors add a little flourish.

F1-SCETI-0846@crop.jpg
Figure 1: FINIS flourish

It’s a nice touch. And we don’t even have to worry about dead trees, so let’s do it.

The above image is extracted from a facsimile of the last page of “The Merchant of Venice” in a First Folio. See lib/paper for a reference to the source image.

Just as the play’s title is only rendered at the beginning of the first scene, this is only rendered at the end of the last one.

.scene <after>
<xslt name="render_finis_if_last_scene"
			input="/static/doc/plays/{play}.xml" 
			section="{section}" />
</after>
<xsl:param name="section" />
<xsl:template match="/play">
	<xsl:if test="$section = sections/section[last()]/@key">
		<p class="scene-finis">finis.</p>
	</xsl:if>       
</xsl:template>

In the folio, the ‘finis’ is a large, centered heading.

font-size 400%
text-align center

Like many headings in the folio, the ‘finis’ is also in all caps. That looks good, but I happen to like the fi ligature you get in lowercase IM Fell.

Just as the top of the first scene leaves some space at the top of the screen (by way of a bubbling margin), this leaves some space at the bottom. In both cases, a special case is signified.

margin-bottom 2em                       // beat p default

Actually, you get 1em by default from a paragraph, but this increases it and also makes the intention explicit.

This helps blend the text with the “paper” background.

color rgba(#111, .8)

We also add the flourish image.

Create a block to work with.

content ''
display block
opacity .8

The slight translusency helps to blend the image with the background.

Reset the font size from parent. For some unknown reason, without this the entire image is scaled.

Give it some arbitrary height. The goal here is simply to avoid too much upscaling.

The drawing is added as a background image.

background-repeat no-repeat
background-position 50% // center horizontally

Ensure that the image is flush on all edges, so that the “blenders” below will work.

These “blenders” help integrate it with the setting.

@import paper
background-image \
	linear-gradient(rgba($paperColor, 1), rgba($paperColor, 0) 3rem),
	linear-gradient(to left, rgba($paperColor, 1), rgba($paperColor, 0) 4rem),
	linear-gradient(to right, rgba($paperColor, 1), rgba($paperColor, 0) 4rem),
	linear-gradient(to top, rgba($paperColor, 1), rgba($paperColor, 0) 4rem),
	url('/static/images/F1-SCETI-0846@crop.jpg')

10 stage directions

<xsl:template mode="scene" match="sd">
  <!-- Can't use "p" here for same reason as above. -->
  <div>
    <xsl:attribute name="class">
      <xsl:text>sd</xsl:text>
      <xsl:if test="../section and not(preceding-sibling::speech)"> osd</xsl:if>
    </xsl:attribute>
    <a class="a" id="{@a}" />
    <i class="text">
      <xsl:apply-templates mode="scene" />
    </i>
    <br class="tty" />
  </div>
</xsl:template>

<xsl:template mode="scene" match="sd/text()">
  <xsl:value-of select="."/>
</xsl:template>

<xsl:template mode="scene" match="enter|exit|manent">

  <xsl:choose>

    <xsl:when test="@role">
      <a>
	<xsl:value-of select="."/>
      </a>                
    </xsl:when>

    <xsl:otherwise>
      <xsl:value-of select="."/>
    </xsl:otherwise>
  </xsl:choose>

</xsl:template>

11 quotes about scenes

Behold, the heavens do ope,
The gods look down, and this unnatural scene
They laugh at.
Coriolanus

Thus with imagined wing our swift scene flies
In motion of no less celerity
Than that of thought.
Henry V

Your patience this allowing,
I turn my glass and give my scene such growing
As you had slept between.
The Winter’s Tale

How many ages hence
Shall this our lofty scene be acted over
In states unborn and accents yet unknown!
Julius Caesar

Footnotes:

1

See the post “xsl:import and xsl:include in stylesheets don’t work on Google Chrome.” As the answer promises, xsl:import does in fact work in Chrome now (although document() doesn’t…), but it’s still an issue in Safari. See also (the visible part of) the post “Safari’s transformToDocument() and xsl:import” on the hyphenated site. My experience is the same: the transform method (transformToFragment) returns null.

about willshake

Project “willshake” is an ongoing effort to bring the beauty and pleasure of Shakespeare to new media.

Please report problems on the issue tracker. For anything else, public@gavinpc.com

Willshake is an experiment in literate programming—not because it’s about literature, but because the program is written for a human audience.

Following is a visualization of the system. Each circle represents a document that is responsible for some part of the system. You can open the documents by touching the circles.

Starting with the project philosophy as a foundation, the layers are built up (or down, as it were): the programming system, the platform, the framework, the features, and so on. Everything that you see in the site is put there by these documents—even this message.

Again, this is an experiment. The documents contain a lot of “thinking out loud” and a lot of old thinking. The goal is not to make it perfect, but to maintain a reflective process that supports its own evolution.

graph of the program

about

Shakespeare

An edition of the plays and poems of Shakespeare.

the works