Output format
beloch fold FILE.bel writes one JSON document in the FOLD format
1, extended with fields under the beloch: prefix as FOLD's
custom-property rule allows. FOLD is the exchange format the origami tools
read (ADR 0029); the extension carries what the model and the language know
and FOLD has no field for. This document is the contract of the file: what
it represents, and which fields it carries.
The output refers to the model by statement ids and to the kernel by module. Neither refers back.
A file is the path, frame by frame
Section titled “A file is the path, frame by frame”The model's meaning of a program is the sequence of states it passes through
(BELOCH.md, "A program is a path"). The file records that sequence: the
top-level dictionary is frame 0, the flat sheet with every crease drawn on it
in paper coordinates, and file_frames holds the foldedForm frames: first
the flat sheet before any statement, then one frame per statement that
moved the paper, each a flat folded state
(def-flat-state) in table coordinates. A
program that folds nothing has the one baseline frame. Frame 0 is the
crease pattern of the final state, whatever the number of frames, and each
folded frame carries its own vertices, edges and faces: an earlier state
has fewer faces than the final crease pattern and cannot share its
indices. A reader that wants only the result takes the last frame; a
reader that wants the diagram sequence takes them all.
A program with several sheets (the sheet-as-value design) keeps this shape: a
frame holds every sheet as its own connected component of the planar graph,
and a field beloch:sheets maps faces to sheet names. An assembled body is
one frame like any other, since the model treats it as one folded state.
This is where the history lives that the model's state does not carry. The file is a record of the run, and no operation of the language reads it.
Standard fields
Section titled “Standard fields”Each frame uses the FOLD vocabulary for what FOLD can express:
vertices_coords,edges_vertices,faces_vertices: the planar graph of the faces of the state, vertices deduplicated by coordinate and each face listed counter-clockwise. Frame 0 is in paper coordinates, every other frame in table coordinates; a program with no crease has the one face of the sheet.edges_assignment:Bfor the sheet boundary,MandVfor folded creases with the letter derived from the state,Ffor a marked crease that has not folded, andJfor a join edge: a flat edge that only divides a non-convex sheet into convex faces, whose two faces FOLD counts as one.Unever occurs, since a state always knows a crease's disposition.edges_faces: per edge, the faces on its sides as indices intofaces_vertices, ascending: one face for a boundary edge, two for every other edge, aJedge included. Faces joined acrossJedges are what FOLD counts as one face, so a reader that wants FOLD's faces merges them there, andM,VandFedges separate them.edges_foldAngle: or in degrees, with FOLD's sign: forV, forM, forF,JandB, so the sign always matchesedges_assignment. On a folded frame these are the hinge angles of that state. Frame 0 carries them too, read from the final state: there they are the target angle of each crease, which FOLD allows on a crease pattern. Without them a consumer that folds the pattern (Origami Simulator, for one) would take the angles from frame 0's geometry, which lies flat and gives everywhere.faceOrders: the layer relation as FOLD encodes it, one triple per pair of overlapping faces with the sign taken relative to the second face's normal. Pairs that do not overlap are absent, as in the model.file_specandfile_creator: the FOLD version the file follows andbelochwith its version.frame_classes,frame_parent,frame_inherit: FOLD's frame bookkeeping; frame 0 is acreasePattern, every other frame afoldedFormthat is a child of frame 0 without inheritance.file_author: the text of the program's@authorannotation (BELOCH-ANNOTATIONS.md), absent when the program has none.frame_unit: the unit the program's file declares (BELOCH.md, "Sheets"), or"unit"when it declares none. It stands in frame 0, and every coordinate of the file is in that unit.
Exact coordinates are rounded to decimal only at serialization; the values the kernel computes stay exact (ADR 0008, 0012).
Beloch's fields
Section titled “Beloch's fields”What the language knows about a state and FOLD cannot say:
beloch:edges: per crease edge, the statement that scored it as an index intobeloch:statements(statement) together with its source span, its construction (which axiom or verb), the names of the points and lines it was built from, and the crease's name if it has one: the fieldsaxiom,sources,span,statement,nameandcrease_id. A crease bound inside a kept instance carries its qualified name,"p1.d"for--dbound inside$p1 = apply …;nameis null for a temp and for a crease of an application that kept no instance. Consumers join on the index; two statements may share a source line, so the span alone leaves the join ambiguous. This is the attribution the model calls provenance (ADR 0019).beloch:source_line, on each folded frame: the source line of the statement that produced the frame.beloch:statements: one entry per executed statement in the order the statements run, a sourcemap from the program to the frames (ADR 0030). Each entry carries thekindthat says which axis it moves, itssource_lineand itsspan, theframe_indexof the frame it reads against, and itsparent.foldandmarkare the writes: the paper moved, or it was scored and stands where it was.bindmoves the program alone, which a point, a construction line, a bundle, a definition and an export all do.applyruns a definition and names it indef; the statements of its body follow it, each with the index of theapplyentry as itsparent, once per execution, and with the span where the body writes them.parentis null at the top level. A reader stepping through the fold sequence walks the writes; a reader of the program walks every entry. A FOLD written beforeparentexisted carries neitherapplyentries nor the bindings of a body.beloch:references: one entry per resolved mention of a crease name in the source, each with thespanit occupies and what it names: acrease_id, oredgefor a paper boundary. The arguments of aflatten, the operands of amap, a filter: every place the program names a crease. The spans a crease's own entry inbeloch:edgescarries say where it was defined; these say where it is used, which no consumer can recover by re-reading the text, since one spelling names different creases inside adefbody and after a--x!rebinding. Deduplicated by (target, span).beloch:annotations: one entry per annotation in the order the statements ran, an annotation in adefbody once per execution (ADR 0029,BELOCH-ANNOTATIONS.md). Each carries itskey, itsnamespaceor null, itsspanandsource_line, and itstarget: the first and the last index intobeloch:statementsit belongs to. The target is one entry, the statement after the annotation, except forstep, whose target runs to the entry before the nextstepor to the last entry. An annotation after the last statement of the program or of adefbody belongs to a state, and its target is null;frame_indexnames that state. The keysauthor,designandsourcebelong to the program as a whole (ADR 0051), and their target is the string"program"; theirframe_indexis 0.argsholds the arguments in order, each an object with itsspanand one oftext,number,word,point(withpaperandtablecoordinates),line(with the table line'scoeffsand thecrease_idwhen the argument names a crease) orflap(with itsfaces, indices into the faces of the frameframe_index, the frame the arguments were read against). A reader that removes this field andfile_authorhas the FOLD of the same program without its annotations.beloch:named_points[].statementandbeloch:named_lines[].statement: the statement that binds the name, as an index intobeloch:statements. Thestepbeside it counts frames and cannot separate two names bound between the same pair of folds. It is null for a name no statement bound, which the four paper corners are. A FOLD written before every statement was logged reports the next state-changing statement instead, which is what the field meant then.beloch:vertices_names,beloch:named_points,beloch:named_lineswithbeloch:named_lines_frame: the names a program gave to points and lines, mapped to vertices and to lines. A line bound with=is given by its coefficients on the table of the step itsstepnames, step 0 being the flat sheet. A crease is given by its line on the table of the last frame, and a crease a later fold has bent has no entry; where a crease lies on the paper is its edges, named inbeloch:edges.beloch:named_lines_framereadscreasePatternfor both, which matches neither (#81).beloch:marks: reference marks that subdivide no face (mark … at,mark … betweenending mid-face), which are creases in the language and no edges in the graph. An entry is{"kind": "seg", "a", "b", "line", "intent", "crease_id"}for a dangling segment with its ends in paper coordinates, or{"kind": "point", "p", "line", "intent", "crease_id"}for a point;lineis the mark's line, for the direction a renderer draws a tick in, andintentthe letter the program wrote beside the mark.beloch:free: every free point (free on … from … at …), keyed by its name, qualified inside a kept instance as inbeloch:edges. An entry is{"t", "endpoints", "source_line"}:tis the exact rational as a string,"1/4", so a reader recovers it exactly, andendpointsthe two ends of the range in paper coordinates, rounded likevertices_coords, so a renderer can offer the point as a slider.beloch:faces_matrix: each face's isometry as a matrix, the restriction of to that face, so a renderer can interpolate between frames without re-deriving it.beloch:inspect: an inventory of creases, segments and flaps of the final state keyed by crease id, for the playground's entity inspector.
Everything under beloch: is optional to a FOLD reader that does not know
Beloch; the standard fields alone describe each state completely.
The trace
Section titled “The trace”beloch fold --trace FILE.bel adds what the evaluator considered on the way
to each result: every candidate a selection chose from, and what removed the
others. Figures that explain an operation read it (issue #51), and so can an
editor that shows the candidates while a program is typed. Without --trace
none of this appears, and every other field is the same with and without it.
beloch:trace: one entry per construction and per write the program evaluates, in the order they run. Every entry carries thestatementit belongs to as an index intobeloch:statementsand theframe_indexof the state it read: for a statement that moves paper the state before it, where the statement's ownframe_indexnames the state after. A statement with a construction and a write, such asfold (map .b onto .c), has two entries, the construction's first.- A construction's entry covers a construction inside a
foldormarkand one on the right-hand side of a binding alike. It carries theaxiomtag as inbeloch:edges, thetowardpoint when the statement names one (atowardline leaves it null), andcandidates: every line that satisfies the construction's alignments, each with itsline(the table line'scoeffsin that state) andremoved_by, the stage of the selection (def-selection) that removed it:"paper"for a line that creases no face, which the model does not count as a candidate at all (def-construction);"heading"for one farther in direction from theheadingline than another;"toward"for one whose side thetowardnames no fold of, or whose landing lies farther from thetowardthan another's;"moving"for one whose side the anchor ofmovingnames no fold of;"moved"for one along which no fold carries out every alignment; and null for one no stage removed.selectedis true on the line the construction yields. For axioms 6 and 7 the entry also carriesconics: the parabolas whose tangents these lines are, each as afocuspoint and adirectrixline, and each candidate that crosses paper carries itslanding: the reflection across it of the point of the first alignment, where that point lands when it lies on the side that folds over. For axiom 6 the entry carriescircle, with thecenter, the point the crease passes through, andthrough, the point that moves: its landings lie where the circle meets the target line. - A construction's entry also records what each stage of the selection
found, so that a figure can draw the stages without repeating them. The
entry carries
alignments, theontoalignments in the order the candidates'attemptsindex them, each with itsspanand its twoobjects: aname, and apointor the tablesegmentsof a line's material (def-material).spansholds the source spans of every alignment (alignments,ontoor not) and of theheading,towardandmovingitems, each span covering the item inside its parentheses, or null where the program has no such item.operandslists the points and lines the construction is built from, the point of athroughincluded, each an object as inalignmentsand placed in the state the construction read.toward_name,moving_nameandsubjectspell thetowardtarget, themovingoperand and thexof(x toward …).moving_pointis where the anchor ofmovinglies on the table when it names a point, and null otherwise.heading_nameandheading_linegive theheadingline and itscoeffs, andtoward_segmentsholds the material of atowardline, empty for atowardpoint. Each candidate carriesremoved_at, the stage that removed it:"paper","heading","side"(the side items name no side of it, or name the same side twice),"moved"(the fold with its side does not carry out every alignment) or"landing"(it does not fold the subject of(x toward …)over, or lands farther from thetowardthan another), and null for one no stage removed. A field of a stage the candidate did not reach, or the program does not use, is null or empty.angleis the angle in degrees between the candidate and theheadingline.sideis the side that folds over, as the sign interms, andside_fromsays where it came from:"toward","moving","alone"for the only side whose fold carries out every alignment, and"first"for the side of the first object of the first alignment where both sides do.attemptslists the sides the moved-material stage tried, two without side items and one otherwise, each with itssideand one value per alignment:0or1for the object that folds onto the other,"already"for a point that lies on the candidate and on its target line, and null where the fold does neither. Beside them each attempt listsmotions, one per alignment: null where no object moves, and otherwise thesourcethat moves and itsimage, both as segments: a point and where it lands; for a line that lands on a point, the place of the line that lands there and the point; for a line that lands on a line, the part of it on the side that folds over and that part reflected.subject_foldssays whether that side folds the subject of(x toward …)over.landedis the landed material the landing stage measured, as segments, a point as a segment of length zero,distanceits distance to thetoward, andnearestthe pair of points that distance lies between, the landed one first. Where several candidates remain, each carriessuggestion: the item that keeps it alone, as the program would write it ("(toward .d)","(--v toward .u)"), chosen asBELOCH-CONSTRUCTIONS.mdstates beside the errors of the selection; null where none does, and on every candidate of a selection that decided. - A write's entry carries
write, one of"fold","reverse"and"flatten", thetermsof the write's definition in the state it read, and thecandidatesit chose from. A region of paper in the terms is a list of polygons, one per face, in table coordinates; a segment is a pair of points. Each candidate carries itsframe, the candidate state as afoldedFormframe of the same shape as those infile_frames, or null where no state exists;removed_by, the rule that removed it or null; andselected, true on the state the write yields. Where several candidates keepremoved_bynull and none isselected, the write was ambiguous and the program failed. fold(def-fold): thetermsare theaxisas a table line'scoeffs, thesidethat moves as the sign, or , of there, themovingset, and theplacement:"top","bottom","over"or"under", the last two with thetargetregion the block is placed against. The moving set is the region as it lies before the fold. A fold chooses no state, so itscandidatesare empty and the state after it is the statement's own frame. A fold that would tear the paper still has its entry, and the file then ends before the fold. Anunfold(def-unfold) reflects one block as a fold does, and its entry has the same shape, withwrite"fold".reverse(def-reverse): thetermsare theaxis, theside, thekind,"inside"or"outside", and thetip. The entry has one candidate per opening of the tip, from the bottom of the tip up, each withspine, a hinge across the opening, as a segment, itshalves, the lower and the upper block, and itsbodiesas two regions each, the lower first, andremoved_by:"letter"when a letter item gives a hinge of the spine's line another letter,"bodies"when a block has no body,"interleaved"when the bodies are not separated, and"crossing"when the reflection is no state.bodiesis null on a candidate removed before it exists, andframeis null on every removed candidate.flatten(def-flatten): thetermsare the vertexpoint. The entry has one candidate per candidate state, each with theraysof its fan that the program gave, itsemergentray or null, and itsstayeras the ends of the two rays that bound the stayer sector, counter-clockwise; a ray is a segment from the vertex. The letters of a candidate are the assignments in its frame.removed_bynames the stage of the selection (open-flatten-selection) that removed it:"opposite"for an emergent ray on the far side of a given ray's line, which the selection falls back to only when no emergent ray on a new line closes the vertex,"toward"for a state whose moved material lies farther from thetowardpoint than another's,"mountains"for one with more mountains on the given rays than another, and"top"for one that puts less of the material toward the point on top.beloch:error: present when the program fails, with themessage, thehint, thespanand thestatementindex of the statement that failed.
With --trace, a program that fails still writes a file: the frames up to
the state the failing statement read, its entry in beloch:statements, and
its trace entries. An ambiguous construction leaves several candidates with
removed_by null and none selected, and so does an ambiguous write; that
is the state a figure draws to show why the program has to choose. The exit
code is that of the failure.
What this document will grow into
Section titled “What this document will grow into”A worked file for the preliminary base, frame by frame, with the fields called out; and the diagram output, the YR-style folding sequence, once it exists.
Erik D. Demaine et al., “FOLD File Format Specification (Version 1.2),” 2023, https://github.com/edemaine/fold.↩