├── .gitattributes
├── .gitignore
├── LICENSE
├── README.md
├── build instructions.txt
├── change.log
├── css
├── font-reference.ttf
├── font.css
├── menuStyle.css
├── place to get icons.url
└── screenStyle.css
├── data
├── name.txt
├── passages.html
├── production.html
└── sketch.html
├── dist
├── 0.2.1
│ └── format.js
├── 0.2.7
│ └── format.js
├── 0.2.8
│ └── format.js
├── 0.2.9
│ └── format.js
├── 0.3.0
│ └── format.js
├── 0.4.0
│ └── format.js
├── 0.4.5
│ └── format.js
└── currentRelease
│ └── format.js
├── format.html
├── format.json
├── gulpfile.js
├── index.html
├── js
├── init.js
├── makePDF.js
├── makepdf.js.bak
├── menu.js
├── new_passage.js.build
├── passage.js
├── passage.js.bak
├── story.js
├── story.js.bak
└── story.js_new.bak
├── lib
├── jquery.js
├── lz-string.js
├── marked.js
├── pdfmake.min.js
├── underscore.js
└── vfs_fonts.js
└── package.json
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
4 | # Custom for Visual Studio
5 | *.cs diff=csharp
6 |
7 | # Standard to msysgit
8 | *.doc diff=astextplain
9 | *.DOC diff=astextplain
10 | *.docx diff=astextplain
11 | *.DOCX diff=astextplain
12 | *.dot diff=astextplain
13 | *.DOT diff=astextplain
14 | *.pdf diff=astextplain
15 | *.PDF diff=astextplain
16 | *.rtf diff=astextplain
17 | *.RTF diff=astextplain
18 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | #################
2 | ## NPM
3 | #################
4 | node_modules/
5 | build/
6 |
7 | #############
8 | ## OS detritus
9 | #############
10 |
11 | # Windows image file caches
12 | Thumbs.db
13 | ehthumbs.db
14 |
15 | # Folder config file
16 | Desktop.ini
17 |
18 | # Recycle Bin used on file shares
19 | $RECYCLE.BIN/
20 |
21 | # Mac horseshit
22 | .DS_Store
23 |
24 | ###################
25 | ## TESTING
26 | ###################
27 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 seansimonanimation
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Screentastic
2 | A Twine 2 Story Format for creating Interactive Screenplays.
3 |
4 | Howdy!
5 |
6 | Here's the basic how-to for using Screentastic
7 |
8 | ## Installation
9 |
10 | -Open Twine 2.
11 | -On the right side, you'll see +story, Import from File, Archive, and Formats. Click on Formats.
12 | -There will be the popup window that shows you all of your currently installed formats. At the top, on the third tab is "Add a New Format". Click that.
13 | -Copy-paste either the folder, or the URL into the box and click "+Add"
14 | -Here's where it gets a little funky. Twine doesn't really know when a Story Format's been added, so just wait for 5-10 seconds and it should be completely loaded.
15 | -X out of the format popup and click on "Formats" again.
16 | -Click on the "Story Formats" tab and Screentastic will show up underneath Sugarcube. There's no icon at this point so it just shows a broken image.
17 |
18 | And that's it! Screentastic is installed in Twine and whenever there is an update, simply overwrite that format.js file and Twine will automatically use the updated format file.
19 |
20 | ## Usage
21 |
22 | Using Twine is pretty simple. There's two main modes: Production mode and Sketch mode.
23 |
24 | In Production mode, Screentastic acts just like a regular screenplay, with links added. It uses its own special kid of markup that looks like so:
25 | #### itm>> content
26 | Itm is the kind of object you need displayed at that point. It could be a character name, some dialogue, a parenthetical... anything.
27 | content is the actual content of the code block.
28 | So for instance, if I have this snippet:
29 | ```
30 | cha>>Dan the man
31 | dia>>I'm the fucken man!
32 | ```
33 | It will show up as if you wrote it with Final Draft, Celtx, or any other screenwriting software.
34 |
35 | Sketch mode, on the other hand is a great place for outlining your ideas. simply make the first line of the first passage "sketch>>" or type "window.sketchMode = true" into the story javascript, and Screentastic will turn every single line of the story into an unordered list item.
36 |
37 | I personally use Sketch mode to write down my story beats, then turn them into screenplay format in another story.
38 |
--------------------------------------------------------------------------------
/build instructions.txt:
--------------------------------------------------------------------------------
1 | to build screentastic:
2 |
3 |
4 |
5 | install node.js
6 | install GnuWin32 ( allow it to wrap into command prompt) (optional step)
7 | Navigate to the downloaded directory in cmd
8 |
9 | run: "npm install" (may have to be run more than once)
10 | run: "gulp"
11 | run: "gulp release"
--------------------------------------------------------------------------------
/change.log:
--------------------------------------------------------------------------------
1 | *************
2 | CHANGE LOG!!!
3 | *************
4 |
5 | v0.1.0
6 | ------
7 | Initial release!
8 |
9 | known bugs:
10 | 1) Links appear all on the same line, for some reason.
11 |
12 | v0.2.1
13 | ------
14 | changes:
15 | --All links now have exactly one line break after them.
16 | --Added parantheticals. par>> activates.
17 | --general maintainence stuffs
18 | --started adding infrastructure for future features.
19 |
20 | known bugs:
21 | --text starts immediately at the top of the #page element, and looks ugly. DE-UGLIFY!
22 |
23 |
24 | v0.2.7
25 | ------
26 | Changes:
27 | --Formatted the #page element to look like an 8.5x11 page!
28 | --Added fun little 3 hole punches on the left side!
29 |
30 | known bugs:
31 | --The Three hole punch uses a unicode character, which does not exist in either Courier Prime or Twine. Need to change to something that renders properly or fix it so that it does.
32 | --There's no error catching for when a passage extends beyond the #page element. Need to add either a scroll bar in the page or seperate out pages. Scroll bar is the lazy fix, multiple page fix is the smart option (smart for printing later).
33 |
34 | v0.2.8
35 | ------
36 | Changes:
37 | --Added a menu! There's nothing in it yet, but it exists! Woo!
38 | --Planned items for menu: Quicksave/load, save to PDF, print. (others, too? There's plenty of room...)
39 |
40 | Known bugs:
41 | --Dropping the menu and simultaneously dropping the #page div destroys the passage data. Gotta find out why... For now, the menu just covers the passage.
42 | --Passage text shows through the window... it should go under (fix with z-index).
43 | --Same bugs from last time.
44 |
45 | v0.2.9/a/b/c
46 | ------------
47 | Changes:
48 | --Added the icons for the menu. They don't work right now and all they do is throw up an alert, telling you that the functionality's not in yet.
49 | --Fixed the spacing on scene headers.
50 | --Fixed the hole punches. They display correctly in the Twine player now.
51 |
52 | Known bugs:
53 | -- Still no fix for the text breaking the bottom of the page. For now, just make extra passages as a workaround. I hope to have this fixed for 0.3.0.
54 | --I need to do something about those massive menu icons. They hurt to look at right now.
55 |
56 | Thoughts:
57 | --I should put in visual themes. That'd be fun. As long as what's on the page isn't changed, we can do whatever!
58 | --base64 is wonderful.
59 |
60 | v0.3.0
61 | ------
62 | Changes:
63 | Added a bunch of new features
64 | automatic page parsing: If your story's passage runs beyond a page, don't worry... Screentastic will automatically add pages as needed.
65 | Sketch Mode: An exciting new feature that allows you to quickly get your ideas out there.
66 | The Menu: The menu items are not functional yet, but we've now got a menu that you can open/close at will.
67 | a bunch of changes under the hood: A lot of the passage handling passage.js has been restructured.
68 | Automatic scrolling to the top: Screentastic now drops you off at the top of the page whenever you click a link.
69 |
70 | known issues:
71 | The page parser's spacing for adding new pages is not always consistent.
72 | The links in the menu don't work. Don't worry, they just haven't been programmed yet. They should be done save for the PDF items by 0.4.0.
73 |
74 | v0.4.0
75 | ------
76 | Changes:
77 | It's been a long time coming, but I've added PDF generation for both Production Mode as well as Sketch Mode!
78 |
79 | known issues:
80 | Generating a PDF doesn't work inside Twine. Only inside browsers.
81 | Sketch mode is pretty spotty on where and when it wants to include unordered list dots. (Might warrant a recode).
82 | Page margins between pages still needs work.
83 |
84 | v0.4.5
85 | ------
86 | Most of the big stuff is in! At this point it's just filling in the gaps, making fixes, and removing obsolete code.
87 | Additions:
88 | Back button
89 | Forward button
90 | Quicksave
91 | Quickload
92 | We now have hotkeys!
93 | hotkey list:
94 | ctrl+left: Back
95 | ctrl+right: Forward
96 | ctrl+down: Quicksave
97 | ctrl+up: Quickload
98 | ctrl+alt+O: Create and open PDF document
99 | ctrl+alt+P: Create and print PDF Document (experimental)
100 | Darkened the icons on the menu bar (All the buttons work now so no reason not to)
101 | Added labels below the icons on the menu bar.
102 |
103 | Fixes:
104 | Fixed hole punches not showing up on dynamically generated pages.
105 | Made the spacing more consistent on the dynamically generated pages. (I think.)
106 |
--------------------------------------------------------------------------------
/css/font-reference.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/seansimonanimation/Screentastic/ceae146dac9b2d94327d141bb8c3225a9b66d325/css/font-reference.ttf
--------------------------------------------------------------------------------
/css/menuStyle.css:
--------------------------------------------------------------------------------
1 | #menuButton {
2 | position: fixed;
3 | height: 35px;
4 | width: 50px;
5 | right: 20px;
6 | color: #555;
7 | border:solid;
8 | border-width: 3px;
9 | border-color: #999;
10 | background-color: #EEE;
11 | text-align: center;
12 | line-height: 50px;
13 | cursor: pointer;
14 | font-size: 500%;
15 | z-index: 6;
16 | -webkit-touch-callout: none;
17 | -webkit-user-select: none;
18 | -khtml-user-select: none;
19 | -moz-user-select: none;
20 | -ms-user-select: none;
21 | user-select: none;
22 | }
23 | .menuHereButton {
24 | top: 98px;
25 | padding-top: 15px;
26 | }
27 | .menuAwayButton {
28 | top:-1px;
29 | padding-top: 15px;
30 | -webkit-transform:rotate(-180deg);
31 | -moz-transform:rotate(-180deg);
32 | -o-transform:rotate(-180deg);
33 | transform:rotate(-180deg);
34 | ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";
35 | filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);
36 |
37 | }
38 |
39 | #menuBar {
40 | position: fixed;
41 | left: -5%;
42 | height: 100px;
43 | width: 110%;
44 | color: #333;
45 | border: solid;
46 | border-width: 3px;
47 | border-color: #999;
48 | background-color: #EEE;
49 | text-align: center;
50 | z-index: 10;
51 | white-space: nowrap;
52 | overflow: hidden;
53 | }
54 |
55 | .menuGone {
56 | top: -110px;
57 | }
58 | .menuHere {
59 | top: -5px;
60 | }
61 | #menuItem {
62 | font-family: 'Screentastic_Icons';
63 | font-size: 400%;
64 | color: #555;
65 | line-height: 100px;
66 | position: relative;
67 | display: inline-block;
68 | margin:0 auto;
69 | top: -1px;
70 | height: 98%;
71 | width: 100px;
72 | background-color:#EEE;
73 | border: solid;
74 | border-color: #999;
75 | cursor:pointer;
76 | }
77 | /*TODO: find a better way to do the button positioning...*/
78 | .backButton {left: 25px;}
79 | .forwardButton { left: 12.5px;}
80 | .quickSaveButton {
81 | }
82 | .quickLoadButton { left: -12.5px; }
83 | .makePDFButton { left: -25px; }
84 | .makePrintButton { left: -37.5px; }
85 |
86 | /* page-moving stuffs is broken atm... TODO: find out why. */
87 | .pageDefaultPos {
88 | }
89 |
90 | .pageMenuPos {
91 | top: 100px;
92 | }
93 |
94 | .buttonlabel {
95 | font-size: small;
96 | font-family: 'CourierPrime';
97 | line-height: 50%;
98 | margin-top: -12px;
99 | }
100 |
--------------------------------------------------------------------------------
/css/place to get icons.url:
--------------------------------------------------------------------------------
1 | [InternetShortcut]
2 | URL=http://app.fontastic.me/#select/Ldi87sJ7uhLvgSagbYS5db
3 |
--------------------------------------------------------------------------------
/css/screenStyle.css:
--------------------------------------------------------------------------------
1 | body { font-family: 'CourierPrime'; background: #AAA; }
2 |
3 | #page {
4 | background: #FFF;
5 | height: 972px;
6 | width: 672px;
7 | border-style: solid;
8 | border-width: 1px;
9 | padding: 72px;
10 | z-index: 5;
11 | position: absolute;
12 | left: 0;
13 | right: 0;
14 | margin-left: auto;
15 | margin-right: auto;
16 | }
17 |
18 | #pageCenter {
19 | width: 100%;
20 | }
21 |
22 | #passageConstruction {
23 | position: absolute;
24 | margin: auto;
25 | display: none;
26 | z-index: 1;
27 | }
28 |
29 | #schCont {
30 | /*character length: 62*/
31 | position: relative;
32 | display: block;
33 | margin-left: 25px;
34 | width: 635px;
35 | text-transform: uppercase;
36 | margin-top: 20px;
37 |
38 | }
39 |
40 | #traCont {
41 | /*character length: 62*/
42 | position: relative;
43 | display: block;
44 | margin-left: 25px;
45 | width: 635px;
46 | text-transform: uppercase;
47 | text-align: right;
48 | margin-top: 20px;
49 |
50 | }
51 |
52 | #actCont {
53 | /*character length: 62*/
54 | position: relative;
55 | display: block;
56 | margin-left: 25px;
57 | margin-top: 20px;
58 | margin-bottom: 10px;
59 |
60 | }
61 |
62 | #diaCont {
63 | /*character length: 34*/
64 | position: relative;
65 | display: block;
66 | margin-left: 150px;
67 | margin-top: -20px;
68 |
69 | }
70 |
71 | #chaCont {
72 | /*character length: 26*/
73 | position: relative;
74 | display: block;
75 | margin-left: 250px;
76 | text-transform: uppercase;
77 | margin-top: 20px;
78 | }
79 |
80 | #parCont {
81 | /*character length: 26*/
82 | position: relative;
83 | display: block;
84 | margin-left: 188px;
85 |
86 | }
87 |
88 | #linkCont {
89 | position: relative;
90 | display: block;
91 | margin-left: 69px;
92 | margin-top: 20px;
93 |
94 | }
95 | #more {
96 | position: relative;
97 | display: block;
98 | margin-left: 300px;
99 |
100 | }
101 |
102 | ul {
103 | word-wrap: break-word;
104 | }
105 |
106 | #pageNumberCont {
107 | /*Future Feature: Page numbers that reflect what'll be seen on the PDF.*/
108 | }
109 |
110 | /*The things below this line are for funsies and are not actually important to making things industry standard*/
111 |
112 | #holePunch {
113 | font-family: 'Screentastic_Icons';
114 | font-size: 125%;
115 | color: #333;
116 | position: absolute;
117 | height: 1122px;
118 | margin-top: -75px;
119 | margin-left: -75px;
120 | width: 100px;
121 | z-index: 6;
122 | text-align: center;
123 | -webkit-touch-callout: none;
124 | -webkit-user-select: none;
125 | -khtml-user-select: none;
126 | -moz-user-select: none;
127 | -ms-user-select: none;
128 | user-select: none;
129 | }
130 |
131 | .tophole {
132 | margin-top: 75px;
133 | }
134 | .midhole {
135 | margin-top: 400px;
136 | }
137 | .bothole {
138 | margin-top: 400px;
139 | }
140 |
--------------------------------------------------------------------------------
/data/name.txt:
--------------------------------------------------------------------------------
1 | An Unreasonably Long Title That Tests The Limits of Everyone's Patience
2 |
--------------------------------------------------------------------------------
/data/passages.html:
--------------------------------------------------------------------------------
1 | sch>> INT. TIME TRAVEL SCHOOL - MORNING
10 | act>> A classroom full of exhausted College Senior Level TIME CADETS sit in their classroom, staring down their PROFESSOR, Mid-30s, wearing a tweed jacket with elbow patches and a bow tie wrap up her lecture.
11 | act>>One student, CHRIS JENKINS, early twenties, wearing his green hoodie with “DR LORDE’S SCHOOL OF TEMPORAL MECHANICS” printed on the front, sits at his desk with his laptop in front, taking notes. Next to Chris, KATHLEEN MASON, mid-20s, skinny as a rail, hair disheveled, wearing the exact same hoodie as Chris, and black makeup, sits completely disinterested. She shakes her head in an attempt to wake herself up.
12 | act>>The professor points her laser pointer to drawings on a whiteboard, demonstrating what she’s saying.
13 | cha>> PROFESSOR
14 | dia>> So to summarize the Bootstrap Paradox... You go back in time to meet your hero Abraham Lincoln because you love the Ghettysburg Address just so much.
15 | act>> She moves the pointer to a terrible drawing of Abraham Lincoln, lying in a hammock, relaxing.
16 | act>>She moves the pointer to a third drawing of someone handing a paper to Lincoln.
17 | cha>>professor (cont'd)
18 | dia>>so you, the time traveler freak out and hand him the address. He delivers. What is the paradox? Chris.
19 | act>>She points to Chris. Chris stands up.
20 | cha>>Chris
21 | dia>>Who wrote the Ghettysburg address?
22 | act>>The prfessor puts her laser pointer in her jacket pocket.
23 | cha>>Professor
24 | dia>>Exactly. Which came first, the chicken or the egg? The ghettysburg address or the time traveler?
25 | act>>The professor checks her watch.
26 | cha>>Professor (cont'd)
27 | dia>>Class is dismissed. Next class, I want a page on how you can avoid runing all of time and space with this little gem.
28 | act>> The TIME CADETS stand and suffle out of the classroom. Chris and Kathleen follow.
29 | cha>>Professor (cont'd)
30 | par>>(yelling)
31 | dia>>And don't forget, stay out of history!
32 | [[Oppose the man|Oppose1]]
33 | [[Oppose the man|Oppose1]]
34 | act>> The boy opposes the man. Everybody cheers.
35 | act>> The boy steps off the stage
36 | cha>> The Boy
37 | dia>> The play is over!
38 |
39 |
--------------------------------------------------------------------------------
/data/production.html:
--------------------------------------------------------------------------------
1 | sch>> INT. TIME TRAVEL SCHOOL - MORNING
10 | act>> A classroom full of exhausted College Senior Level TIME CADETS sit in their classroom, staring down their PROFESSOR, Mid-30s, wearing a tweed jacket with elbow patches and a bow tie wrap up her lecture.
11 | act>>One student, CHRIS JENKINS, early twenties, wearing his green hoodie with “DR LORDE’S SCHOOL OF TEMPORAL MECHANICS” printed on the front, sits at his desk with his laptop in front, taking notes. Next to Chris, KATHLEEN MASON, mid-20s, skinny as a rail, hair disheveled, wearing the exact same hoodie as Chris, and black makeup, sits completely disinterested. She shakes her head in an attempt to wake herself up.
12 | act>>The professor points her laser pointer to drawings on a whiteboard, demonstrating what she’s saying.
13 | cha>> PROFESSOR
14 | dia>> So to summarize the Bootstrap Paradox... You go back in time to meet your hero Abraham Lincoln because you love the Ghettysburg Address just so much.
15 | act>> She moves the pointer to a terrible drawing of Abraham Lincoln, lying in a hammock, relaxing.
16 | act>>She moves the pointer to a third drawing of someone handing a paper to Lincoln.
17 | cha>>professor (cont'd)
18 | dia>>so you, the time traveler freak out and hand him the address. He delivers. What is the paradox? Chris.
19 | act>>She points to Chris. Chris stands up.
20 | cha>>Chris
21 | dia>>Who wrote the Ghettysburg address?
22 | act>>The prfessor puts her laser pointer in her jacket pocket.
23 | cha>>Professor
24 | dia>>Exactly. Which came first, the chicken or the egg? The ghettysburg address or the time traveler?
25 | act>>The professor checks her watch.
26 | cha>>Professor (cont'd)
27 | dia>>Class is dismissed. Next class, I want a page on how you can avoid runing all of time and space with this little gem.
28 | act>> The TIME CADETS stand and suffle out of the classroom. Chris and Kathleen follow.
29 | cha>>Professor (cont'd)
30 | par>>(yelling)
31 | dia>>And don't forget, stay out of history!
32 | [[Oppose the man|Oppose1]]
33 | [[Oppose the man|Oppose1]]
34 | act>> The boy opposes the man. Everybody cheers.
35 | act>> The boy steps off the stage
36 | cha>> The Boy
37 | dia>> The play is over!
38 |
--------------------------------------------------------------------------------
/data/sketch.html:
--------------------------------------------------------------------------------
1 | sketch>>
4 | The time, 5pm. We see a rundown house in a bad neighborhood.
5 | Carlos is packing himself a lunch in his backpack in the kitchen.
6 | He walks over to his parents who are playing poker with their friends.
7 | Carlos asks his mom and dad if they can give him a ride to a late night school trip to the museum.
8 | His dad claims that the car is still in the shop and that Carlos could use some exercise (says this with chips in his mouth).
9 | As Carlos ties his shoes at the front door, he can hear his parents talk about him. “Stupid boy is too needy that’s what he is. Don’t know why we even had him.” His mom replies, “We needed someone to take care of the laundry. That’s what adoption is isn’t it? Free manual labor.” They all start to laugh.
10 | Carlos walks out the door. We see his dad’s car in the garage.
11 | Carlos arrives at the museum but arrives too late.
12 | We see everyone from class leaving the building and heading home with their friends and family.
13 | To make matters worse, thunder breaks loose and begins to rain on him.
14 | He heads underneath the museum’s gate entrance to take shelter.
15 | He decides to have the sandwich he packed.
16 | A stray dog walks over him staring hungrily at Carlos’ meal.
17 | Carlos takes pity and shares a small piece of his sandwich.
18 | The dog instead takes a bite into his larger portion and runs off into the museum.
19 | Carlos chases after it.
20 | A pair of hollow eyes watches from the distance.
21 | Carlos looses the dog and decides to leave.
22 | The door gate doesn’t open trapping Carlos inside the museum.
23 | Carlos tries to find security to help let him back outside.
24 | As he walks through the halls past the art displays, playful shadows shaped like wolves begin to follow Carlos from behind.
25 | Carlos comes across a display featuring Native American relics.
26 | Carlos notices one of the pieces missing from the shelf.
27 | He walks up to it and hears a crack sound from his feet.
28 | He looks down and realizes he stepped on the missing display.
29 | The shadows from early lurk in from behind with out Carlos noticing.
30 | Carlos picks up have a piece of a coin with a dragonfly on it.
31 | Two of the shadows give a playful smile to one another and begin to run around in a circle around Carlos while he’s not looking.
32 | Carlos begins to hear security near by. He worries that he’ll be blamed from damaging museum property.
33 | Carlos tries to make a run for it but his feet begin to sink. The floor starts to dissolve into sand engulfing Carlos in.
34 | He manages to pull himself out, but then notices he is no longer in the museum. Instead he is in a small wasteland near the ocean.
35 | Carlos is surrounded by shadows causing him to freak out in fear.
36 | [[go to next page|secondPage]]They then stop and clear a path for their master to step forward. It is coyote spirit towering over Carlos.
37 | Carlos flips out saying “What’s are wolves doing in the city!?”
38 | The coyote snarls and is annoyed. She transforms into a young, girl close to Carlos’ age. She walks up to him and analyzes him.
39 | She asks to herself, “How did a human doing in the Wasteland?””
40 | She turns her head toward her pack making whistle noises and smirks to act innocent. “Figures.” she says.
41 | Carlos asks, “Excuse me, wolf-lady. Hi, big question. What’s going on?”
42 | “Since you’re new, let me educate. One, I’m a coyote, not a wolf. There’s a difference. And two, my name is Rein. Three, you’re in the Wasteland of the Spirits. And four, you smell like pancakes and tuna-milk.”
43 | Carlos: “What does that last part have to do with-” Rein drops him.
44 | Rein then asks what he has in his hands.
45 | Carlos shows her and sees the broken talisman. Rein asks what he did with the other half. Carlos tells him he found it like this and it’s broken.
46 | She turns to her minions and demands a confession to whoever took the other half to come forward.
47 | Rein explains that her pack can be difficult to tame. And that they enjoy messing around in the human realm at night. They love taking stuff and burring in the woods. (Even though there suppose to give anything they take and give it for her to have.)
48 | The talisman he has is a key that can take anyone between the human and spirit realm. But he needs the other fragment to get back.
49 | Carlos asks for her to take him to the woods. Rein refuses saying it’s not her concern.
50 | Carlos lists everything that’s gone wrong to him today, and points that it was her stupid pets fault that he got into this and that she needs to own up.
51 | Rein roles her eyes and submits to being his guide.
52 | Carlos then asks if he can ride her, but Rein says no.
53 | They walk on foot till they reach a dead tree forest.
54 | Carlos is a bit uncomfortable not being familiar with his new surrounding.
55 | Rein tells him to man up and that life always has new twists and turns that have trouble adjusting. She takes Carlos himself as an example for crashing her turf and had plans on taking a break from taking care of her pets.
56 | Carlos then asks why she puts up with those little shadows that keep trolling her.
57 | Rein explains that they maybe hard to control, but they’re like family to her.
58 | Rein picks up a scent, which leads to a giant hollow tree.
59 | Inside is a load of garbage from the human world.
60 | Carlos tries digging through to find it. Rein tells him that it’s going to take a century at his pace.
61 | Suddenly, a worm-like tale grabs Rein and pulls her in. Emerging from the trash is a giant opossum monster with Rein in coiled in its tail. Carlos stutters in fear.
62 | The opossum accuses Rein of defiling his home.
63 | Carlos steps in and says that they’ll clean the mess up.
64 | The opossum agrees. Rein gives a sour annoyed look at Carlos saying that she hates cleaning.
65 | Rein and Carlos help dispose of all the garbage, but Carlos hasn’t managed to find the other fragment.
66 | The opossum then grabs Carlos and takes away his fragment. He decides that Rein can leave, but not him.
67 | The opossum compliments on Carlos’ service and could use a human servant for tiding up. And when he gets old he’ll eat his remains and use his bones keep on working.
68 | Infuriated, Rein’s aura grows around her taking the form of a giant coyote. She proceeds to bite the opossum by the tail and trash him like a chew toy till it dissolves into moss.
69 | Rein criticizes to Carlos that this is what happens when you don’t say no to others. They take advantage of you.
70 | Carlos apologies saying that he’s never been used to others helping him in return so much.
71 | Rein then hugs Carlos and comforts him. She puts in his hand the other fragment he needs.
72 | Rein then heads back to her turf and wishes him for the best of luck before he leaves.
73 | After Rein vanishes, Carlos takes a deep quiet pause.
74 | [[Go to next page|thirdPage]]He is now back home outside the museum.
75 | Carlos looks into his hand and sees the talisman has been reassembled.
76 | He returns home and finds his foster parents watching TV. They don’t seem to have notice how long he’s been absent. Carlos heads up to his room sitting on his bed.
77 | His mom yells at Carlos and tells him to fix the antenna on the roof. Carlos ignores her.
78 | He pulls out the talisman from the museum and pauses for a moment.
79 | Back in the spirit realm, Rein is disciplining her minions.
80 | Rein picks up on a familiar sent. She turns and finds Carlos standing in front of her.
81 | Rein asks why has he returned?
82 | Carlos tells her that he realizes that he’s found his true home and has decided that he wants remain in the spirit realm.
83 | Rein jokes and comments that what he’s doing is really selfish which Carlos replies with a simple “yup.”
84 | The End.
85 |
86 |
--------------------------------------------------------------------------------
/format.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
sch>> INT. TIME TRAVEL SCHOOL - MORNING
40 | act>> A classroom full of exhausted College Senior Level TIME CADETS sit in their classroom, staring down their PROFESSOR, Mid-30s, wearing a tweed jacket with elbow patches and a bow tie wrap up her lecture.
41 | act>>One student, CHRIS JENKINS, early twenties, wearing his green hoodie with “DR LORDE’S SCHOOL OF TEMPORAL MECHANICS” printed on the front, sits at his desk with his laptop in front, taking notes. Next to Chris, KATHLEEN MASON, mid-20s, skinny as a rail, hair disheveled, wearing the exact same hoodie as Chris, and black makeup, sits completely disinterested. She shakes her head in an attempt to wake herself up.
42 | act>>The professor points her laser pointer to drawings on a whiteboard, demonstrating what she’s saying.
43 | cha>> PROFESSOR
44 | dia>> So to summarize the Bootstrap Paradox... You go back in time to meet your hero Abraham Lincoln because you love the Ghettysburg Address just so much.
45 | act>> She moves the pointer to a terrible drawing of Abraham Lincoln, lying in a hammock, relaxing.
46 | act>>She moves the pointer to a third drawing of someone handing a paper to Lincoln.
47 | cha>>professor (cont'd)
48 | dia>>so you, the time traveler freak out and hand him the address. He delivers. What is the paradox? Chris.
49 | act>>She points to Chris. Chris stands up.
50 | cha>>Chris
51 | dia>>Who wrote the Ghettysburg address?
52 | act>>The prfessor puts her laser pointer in her jacket pocket.
53 | cha>>Professor
54 | dia>>Exactly. Which came first, the chicken or the egg? The ghettysburg address or the time traveler?
55 | act>>The professor checks her watch.
56 | cha>>Professor (cont'd)
57 | dia>>Class is dismissed. Next class, I want a page on how you can avoid runing all of time and space with this little gem.
58 | act>> The TIME CADETS stand and suffle out of the classroom. Chris and Kathleen follow.
59 | cha>>Professor (cont'd)
60 | par>>(yelling)
61 | dia>>And don't forget, stay out of history!
62 | [[Oppose the man|Oppose1]]
63 | [[Oppose the man|Oppose1]]
64 | act>> The boy opposes the man. Everybody cheers.
65 | act>> The boy steps off the stage
66 | cha>> The Boy
67 | dia>> The play is over!
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
--------------------------------------------------------------------------------
/js/init.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 |
4 |
5 | $(document).ready(function() {
6 | window.bypassError = false; //one of the callbacks in pdfmake activates Screentastic's built-in error handler and destroys #page's content.
7 | pdfMake.fonts = {CourierPrime: { normal: 'CourierPrime.ttf' }};
8 | window.story = new Story($('tw-storydata'));
9 | $.each(window.story.content, function(pasid, pasobj){
10 | if (pasobj !== undefined) {
11 | pasobj.parsePassage(); //uses the pdfmake library's built-in functions to auto-parse for lines and pages for us. It's beautiful!
12 | }
13 | });
14 | window.story.start();
15 | });
16 |
17 |
18 |
--------------------------------------------------------------------------------
/js/makePDF.js:
--------------------------------------------------------------------------------
1 | //a dumb module that makes PDF documents from existing story stuff.
2 |
3 | 'use strict';
4 |
5 | //var docDefinition = {content: ['This is a standard paragraph, using default style',{ text: 'This paragraph will have a bigger font', fontSize: 15 },{text: ['This paragraph is defined as an array of elements to make it possible to ',{ text: 'restyle part of it and make it bigger ', fontSize: 15 },'than the rest.']}]};
6 |
7 |
8 |
9 |
10 | function makePDF(print) {
11 | var allContent = window.storyData[0];
12 | var a = allContent;
13 | var i = 0;
14 | var c = 0;
15 | var s = 0;
16 | var ss = 0;
17 | var sectionName = '';
18 | var pasid=0;
19 | var tag='';
20 | var content = '';
21 | var sections = []; //an array containing objects containg all sections.
22 | /*
23 | proper format:
24 | [{name:"start",pid:1,tags:"",content:"stuff"},{name:"page2",pid:2,tags:"",content:"stuff"}] and so on and so forth...
25 | */
26 | for (i=2; i < (a.childElementCount); i++) {
27 | sectionName = a.children[i].attributes.name.value;
28 | pasid = parseInt(a.children[i].attributes.pid.value);
29 | tag = a.children[i].attributes.tags.value;
30 | content = _.unescape(a.children[i].innerHTML);
31 | content = content.replace(/\/\*.*\*\//g, ''); //removes //comments
32 | content = content.replace(/^\/\/.*(\r\n|\n)?/g, ''); // to avoid clashes with URLs, lines must start with these
33 | sections[i-2] = {name:sectionName, pid: pasid, tags: tag, source: content};
34 | }
35 | var pdfDocDef = {
36 | content: [],
37 | defaultStyle: { font: 'CourierPrime' },
38 | styles: {
39 | sketch : {margin: [ 0,0,-25,0 ]},
40 | sch: {margin: [0, 10, 0, 0]},
41 | tra: {
42 | alignment: "right",
43 | margin: [0,10, 0, 0]
44 | },
45 | cha: { margin: [190, 10, 144, 0]},
46 | dia: { margin: [110, 0, 110, 0], width: 324},
47 | act: { margin: [0, 10, 0, 0]},
48 | par: { margin: [144,0,110,0]},
49 | link: {
50 | fontSize: 16,
51 | margin: [0,20,0,0]
52 | },
53 | },
54 | pageMargins: [70,70],
55 | pageSize: 'LETTER',
56 | };
57 | var runningTotal = 0;
58 | for (i=0; i>(.*)(\r\n|\n)?|\[\[(.*?)\]\](\r\n|\n)?)/g; //both the link grabber and the text grabber combined!
184 | var sourceMatches = unes.match(lineRegExp); //returns an array of all line matches where the lines begin with itm>>.
185 | var manipstring = '';
186 | var lineObj = {};
187 | var i;
188 | var textExists = true;
189 | var lastItem;
190 | var lineType;
191 | var lineContent;
192 | var target;
193 | var targetBookmark;
194 | try {
195 | textExists = true;
196 | for (i=0; i < sourceMatches.length; i++) {
197 | manipstring = sourceMatches[i];
198 | if (manipstring.substring(0,2) == "[[") { //It's a link!
199 | lineType = "link";
200 | var barIndex = manipstring.indexOf('|');
201 | var endIndex = manipstring.indexOf(']]');
202 | targetBookmark = manipstring.slice(barIndex + 1,endIndex);
203 | lineContent = manipstring.slice(2, barIndex);
204 | } else {
205 | lineType = manipstring.substring(0,3);
206 | lineContent = manipstring.substring(5);
207 | }
208 | if (lineType == "sch") {
209 | lineContent = lineContent.toUpperCase();
210 | } else if (lineType == "tra") {
211 | lineContent = lineContent.toUpperCase();
212 | } else if (lineType == "cha") {
213 | lineContent = lineContent.toUpperCase();
214 | } else if (lineType == "par") { //This chunk of code is a smart parenthases parser that makes sure that parenthases are always there.
215 | var matches = lineContent.match(/\s?(\()?([^)]*)(\))?$/);
216 | if (matches.length == 1) {
217 | lineContent = "(" + lineContent + ")";
218 | } else if (matches.length == 2) {
219 | if (matches[0] == "(") {
220 | lineContent = lineContent + ")";
221 | } else {
222 | lineContent = "(" + lineContent;
223 | }
224 | }
225 |
226 | } else if (lineType == "dia") {
227 |
228 |
229 | } else if (lineType == "act") {
230 |
231 | } else if (lineType == "link") {
232 | lineContent = lineContent + ": Please go to page ";
233 | } else { //error
234 | lineContent = "(There has been an error in your markup descriptor) " + lineType + ">> " + lineContent;
235 | }
236 |
237 |
238 | if (i == (sourceMatches.length - 1)) {
239 | lastItem = true;
240 | } else {
241 | lastItem = false;
242 | }
243 |
244 |
245 | if (lineType == "link") {
246 | if (i === 0) {
247 | lineObj = {text: lineContent, style: lineType, target: targetBookmark, last : lastItem, bookmark: Section.name};
248 | } else {
249 | lineObj = {text: lineContent, style: lineType, target: targetBookmark, last : lastItem};
250 |
251 | }
252 | } else {
253 | if (i === 0) {
254 | lineObj = {text: lineContent, style: lineType, last : lastItem, bookmark: Section.name};
255 | } else {
256 | lineObj = {text: lineContent, style: lineType, last : lastItem};
257 | }
258 | }
259 | sourceMatches[i] = lineObj;
260 | }
261 | } catch(err) {
262 | textExists = false;
263 | }
264 | if (textExists === false) {
265 | sourceMatches = {text: "This section contains no data."}; //error catching, yay! Also lazy HTML! Yay!
266 | }
267 | return sourceMatches;
268 | }
269 |
270 |
271 | function pdfSketchParser (Section) {
272 | var unes = Section.source;
273 | var i = 0;
274 | var s = 0;
275 | var heightRegEx = /.*(\r\n|\n)?/g;
276 | unes = unes.replace(/sketch>>.*(\n|\r\n)?/g, '');
277 | var itemArr = unes.match(heightRegEx);
278 | Section.source = itemArr;
279 | return Section;
280 | };
281 |
--------------------------------------------------------------------------------
/js/makepdf.js.bak:
--------------------------------------------------------------------------------
1 | //a dumb module that makes PDF documents from existing story stuff.
2 |
3 | 'use strict';
4 |
5 |
6 | function makePDF(print) {
7 |
8 | var allContent = window.storyData[0];
9 | var a = allContent;
10 | var i = 0;
11 | var c = 0;
12 | var s = 0;
13 | var sectionName = '';
14 | var pasid=0;
15 | var tag='';
16 | var content = '';
17 | var sections = []; //an array containing objects containg all sections.
18 | /*
19 | proper format:
20 | [{name:"start",pid:1,tags:"",content:"stuff"},{name:"page2",pid:2,tags:"",content:"stuff"}] and so on and so forth...
21 | */
22 | for (i=2; i < (a.childElementCount); i++) {
23 | sectionName = a.children[i].attributes.name.value;
24 | pasid = parseInt(a.children[i].attributes.pid.value);
25 | tag = a.children[i].attributes.tags.value;
26 | content = _.unescape(a.children[i].innerHTML);
27 | content = content.replace(/\/\*.*\*\//g, ''); //removes //comments
28 | content = content.replace(/^\/\/.*(\r\n?|\n)/g, ''); // to avoid clashes with URLs, lines must start with these
29 | sections[i-2] = {name:sectionName, pid: pasid, tags: tag, source: content};
30 | }
31 |
32 | for (i=0; i 672) {
104 | newstring = newstring + "\r\n";
105 | tempPassage.innerHTML = "";
106 | }
107 |
108 | }
109 | }
110 | itemArr[i] = newstring;
111 | tempPassage.innerHTML = oldstring + newstring;
112 | oldstring = oldstring + newstring;
113 | tempHeight = tempPassage.clientHeight;
114 | if (tempHeight > 900) {
115 | pageMarker = pageMarker.push(i);
116 | oldstring = '';
117 | newstring = '';
118 | }
119 | tempPassage.innerHTML = '';
120 | //Let's format this properly now.
121 | tempHeight = 0;
122 | for (i=0; i>)(.*)$|\[\[(.*?)\|(.*?)\]\]$)/gm; //both the link grabber and the text grabber combined!
71 | var lineRegExpL = /^((\w{3})(>>)(.*)$|\[\[(.*?)\|(.*?)\]\]$)/;
72 | var sourceMatches = original.match(lineRegExp); //returns an array of all line matches where the lines begin with itm>> or are links.
73 | var i;
74 | for (i=0; i>HAHA! HI!", "dia", ">>", "HAHA! HI!"]
81 | sourceMatches[i] = {text: sourceMatches[i][3], style: sourceMatches[i][1]};
82 | } else if (sourceMatches[i].length == 3){
83 | //regular items should have 4 items in their array at this point. Format: ["[[target|display]]","target","display"]
84 | sourceMatches[i] = {text: sourceMatches[i][3], target: sourceMatches[i][1], style: "link"};
85 |
86 | } else {
87 | sourceMatches[i] = {text: "There is a problem with this item.", style: "err"};
88 | }
89 | }
90 | console.log(sourceMatches);
91 | return sourceMatches;
92 | },
93 | _sketch: function(original) {
94 | if (original.slice(0,8) == "sketch>>" ) {
95 | original = original.slice(8);
96 | }
97 | // console.log(original);
98 | var globalLineReg = /(^\[\[(.*?)\|(.*?)\]\]$|^.+$)/gm;
99 | var localLineReg = /(^\[\[(.*?)\|(.*?)\]\]$|^.+$)/;
100 | var sourceMatches = original.match(globalLineReg); //returns an array of all lines and links.
101 | // console.log(sourceMatches);
102 | var i;
103 | for (i=0; i' + display + '' + '';
126 | } else {
127 | finishedLink = '
" + fullBring;
167 | }
168 | console.log(fullBring);
169 | return fullBring;
170 | },
171 |
172 |
173 |
174 |
175 | //Helper functions are here. They are methods of Passage.
176 | /*
177 | A helper function that is connected to passage templates as $. It acts like the jQuery $ function, running a script when the passage is ready in the DOM. The function passed is also bound to div#page for convenience. If this is *not* passed a single function, then this acts as a passthrough to jQuery's native $ function. @method _readyFunc @return jQuery object, as with jQuery() @private
178 | */
179 |
180 |
181 | _formatArray: function(input, positions, lineType, page) {
182 | //This function formats non-dialogue-driving lines: AKA cha, act, sch, tra. par and dia are handled within the parent function.
183 | var inputArr = [];
184 | var output = '';
185 | var i=0;
186 | var s=0;
187 | var ss=0;
188 | var lineLength;
189 | var addPageLine = '';
190 | var addingPages = false;
191 | if (typeof(input) != "string" || typeof(positions) !="object" || typeof(lineType) != "string") {
192 | return "Something is wrong with your inputs.";
193 | }
194 | switch (lineType) {
195 | case "cha":
196 | lineLength = 34;
197 | break;
198 | case "act":
199 | lineLength = 65;
200 | break;
201 | case "sch":
202 | lineLength = 65;
203 | break;
204 | case "tra":
205 | lineLength = 65;
206 | break;
207 | }
208 |
209 | if (lineType == "cha" || lineType == "sch" || lineType == "tra"){
210 | input = input.toUpperCase();
211 | }
212 |
213 | if (positions.length === 1){
214 | inputArr[0] = input;
215 | } else {
216 | ss=0;
217 | for (i=0; ss page){
246 | //always put it at the beginning...
247 | addPageLine = "
";
184 | },
185 |
186 | _linkMachine: function(original) { //insert code for links!
187 | var linkHunter = /\[\[(.*?)\]\]((\r\n|\n)*)/;
188 | var liMat = original.match(linkHunter)[1]; //returns a string of "display|target"
189 | var finishedLink;
190 | //[[links]]... Snowman's link code made no goddamn sense... so I rewrote it. HAHA! (notes... add the newline possibility to the regex.)
191 | try {
192 | this.linksExist = true;
193 | var display = liMat.slice(0, liMat.indexOf('|')); //second index to bar
194 | var target = liMat.slice(liMat.indexOf('|') + 1); //bar to last.
195 | if (/^\w+:\/\/\/?\w/i.test(target)) {
196 | finishedLink = '
" + lineArr.join(""); //The )( is so we can easily tell it later.
253 | } else {
254 | return "
" + lineArr.join("");
255 | }
256 | } else {
257 | return lineArr.join("");
258 | }
259 |
260 |
261 | //Let's save this old, bad chunk of code for now.
262 | /* *****KNOWN ISSUE*****
263 | The page parser can really only guess at what the final result will be, and it seems to find an arbitrary place
264 | to put the pagemaking code each time. I need to figure out an exact way for the parser to guess accurately.
265 | Until then, it works, just the distances between the pages and here the pages actually split seem arbitrary to the
266 | end user.
267 | *\///remove backslash to uncomment
268 |
269 |
270 | var tempPassage = document.getElementById("passageConstruction");
271 | tempPassage.innerHTML = ""; //Element needs to be cleared out before we can begin.
272 | var tempHeight = 0;
273 | var heightRegEx = /.*(\r\n|\n)?/g;
274 | var wordRegEx = /
275 | var itemArr = original.match(heightRegEx);
276 | var heightSubtractor = 0;
277 | var pageCounter = 1;
278 | var result = '';
279 | var pageDistance = [];
280 | var newstring = '';
281 | var changePageArr = [];
282 | var firstPart = '';
283 | var breakoff = '';
284 | var secondPart = '';
285 | var pageChangeArr = [];
286 | var pageBreak = '';
287 | //We need to build the "#passageConstruction" div character by character (used to be line by line), test the height, and add pages based on that height. To do that, we need to make the tempPassage workable. AKA not display: hidden;
288 | tempPassage.style.position = "absolute";
289 | tempPassage.style.visibility = "hidden";
290 | tempPassage.style.display = "block";
291 | tempPassage.style.width = "672px";
292 | tempPassage.style.left = "0px";
293 | tempPassage.style.top = "0px";
294 | for (i=0; i 900) {
310 | pageDistance = 972 - tempHeight + 82;
311 | if (window.sketchMode === false ) {
312 | //instead of breaking our flow, let's make a new object now and inject everything later.
313 | //What we're doing is inserting the page break at the beginning of the word.
314 | pageBreak = "