Documentation
¶
Overview ¶
Package book checks and builds the book deliverable of an lfm project: a researched concept in deliverables/book/concept.md, chapters written one at a time from it, and the finished EPUB and PDF that buyers download from a page at an unlisted path.
The book follows the page's method. Its concept cites the project's research by ID, its chapters are checked for structure, length and the stock phrases of generated prose, and it is only built once every chapter exists. Until then the download page tells buyers that their copy is being written.
Index ¶
- Constants
- Variables
- func Channels() []string
- func Distribution(r Report, b Built, p Printed, day string) (map[string][]byte, []string, []diagnostic.Diagnostic)
- func DownloadPage(plan Plan, cfg Config, files []deliver.File) []byte
- func Gutter(pages int) float64
- func KDPDescription(md string) string
- func KDPSpine(pages int, paper string) float64
- func LuluSpine(pages int) float64
- func PlainText(md string) string
- func Present(p project.Project) bool
- func PrintDPI(pixels [2]int, inches [2]float64) int
- func Rules() []diagnostic.RuleInfo
- func SVGSize(data []byte) (float64, float64, error)
- func StoreCover(src, previous []byte) ([]byte, error)
- func ValidISBN(s string) bool
- func WrapFile(key string) string
- func Wraps(r Report, pages int) []string
- type Built
- type Chapter
- type Config
- type Image
- type Listing
- type Matter
- type Objection
- type Plan
- type Price
- type PrintOptions
- type Printed
- type Reader
- type Report
- type SourceError
- type Summary
- type Wording
Constants ¶
const ( Dir = "deliverables/book" ConceptFile = Dir + "/concept.md" ChaptersDir = "chapters" ImagesDir = "images" StyleFile = "book.css" )
Layout of the deliverable inside a project.
const ( MinChapters = 3 MinObjections = 3 MinVoices = 8 // distinct voices cited MinPeers = 3 // distinct competing books or guides cited MinJobWords = 4 MinWords = 300 MaxWords = 20000 WordTolerance = 0.35 // a chapter may run this far over or under its target CoverWidth = 1600 CoverHeight = 2560 )
Minimums the concept is held to.
const ( RuleConfig = "book.config" RuleConcept = "book.concept" RuleEvidence = "book.evidence" RuleOpen = "book.open" RuleChapter = "book.chapter" RuleCopy = "book.copy" RuleValue = "book.value" RuleMachine = "book.machine" RuleImages = "book.images" RuleDelivery = "book.delivery" RuleBuild = "book.build" RuleLayout = "book.layout" RuleFonts = "book.fonts" RulePDF = "book.pdf" RuleListing = "book.listing" RuleChannels = "book.channels" )
Rule IDs.
const ( MaxDescription = 4000 // KDP, counted as the HTML it receives MinDescription = 200 MaxShort = 300 MaxBackCover = 1200 MaxKeywords = 7 // KDP MaxKeywordLength = 50 MaxTags = 13 // Etsy MaxTagLength = 20 MaxCategories = 3 MaxTitleLength = 200 // KDP, title and subtitle together )
Store limits the listing is held to; the strictest channel sets each one.
const Bleed = 0.125
Bleed is the margin beyond the trim that print covers extend into.
const ListingFile = Dir + "/listing.md"
ListingFile holds the store texts of the book: descriptions, keywords, categories, prices and the AI disclosure, written once and rendered into the format and limits of every channel.
const MaxCoverBytes = 5 << 20
MaxCoverBytes is the largest store cover KDP takes.
Variables ¶
var ( ChapterColumns = []string{"#", "Title", "Job", "Beats", "Words", "File"} ImageColumns = []string{"Image", "Chapter", "Job", "Art direction", "File"} )
Columns of the tables.
var FictionSections = []concept.SectionSpec{ {Name: "Reader"}, {Name: "Premise"}, {Name: "Cast"}, {Name: "World"}, {Name: "Arc"}, {Name: "Hooks"}, {Name: "Voice"}, {Name: "Chapters"}, {Name: "Matter", Optional: true}, {Name: "Imagery"}, {Name: "Look"}, {Name: "Qualities", Optional: true}, {Name: "Changelog", Optional: true}, }
FictionSections describe a story plan.
var KDPTrims = map[string]bool{"5x8in": true, "5.5x8.5in": true, "6x9in": true, "A4": true, "letter": true}
KDPTrims are the paperback trims KDP prints, of those lfm offers.
var ListingSections = []concept.SectionSpec{
{Name: "Description"},
{Name: "Short description"},
{Name: "Back cover"},
{Name: "Author"},
{Name: "Keywords"},
{Name: "Tags"},
{Name: "Categories"},
{Name: "Prices"},
{Name: "AI"},
}
ListingSections are the sections of listing.md in their required order.
var Sections = []concept.SectionSpec{ {Name: "Reader"}, {Name: "Promise"}, {Name: "Big idea"}, {Name: "Objections"}, {Name: "Hooks"}, {Name: "Voice"}, {Name: "Devices"}, {Name: "Cases", Optional: true}, {Name: "Chapters"}, {Name: "Matter", Optional: true}, {Name: "Imagery"}, {Name: "Look"}, {Name: "Qualities", Optional: true}, {Name: "Changelog", Optional: true}, }
Sections of the book concept in their required order. The format follows what makes a useful nonfiction book: a scope (reader, promise, who it is not for, what it will not cover), one idea the market lacks, hooks, a voice with exact phrases, recurring devices, and chapters that each have one job.
var Trims = map[string][2]float64{
"5x8in": {5, 8},
"5.5x8.5in": {5.5, 8.5},
"6x9in": {6, 9},
"A5": {5.83, 8.27},
"A4": {8.27, 11.69},
"letter": {8.5, 11},
}
Trims are the page formats the PDF can be printed in, with their size in inches.
Functions ¶
func Channels ¶
func Channels() []string
Channels returns the keys of the channels lfm prepares, in order.
func Distribution ¶
func Distribution(r Report, b Built, p Printed, day string) (map[string][]byte, []string, []diagnostic.Diagnostic)
Distribution assembles the store packages: every file once at the top, a guide per channel in stores/ naming the files it takes and every field in its format, and a README over all of them. Channels that refuse the book are listed in the README only.
func DownloadPage ¶
DownloadPage renders the unlisted page buyers land on after paying. With no files the book is still being written, and the page says so.
func Gutter ¶
Gutter is the inside margin of a paperback with pages pages: KDP's minimum gutter for the page count plus a quarter inch, and never below three quarters of an inch, which also meets IngramSpark's half-inch margins.
func KDPDescription ¶
KDPDescription renders Markdown into the HTML KDP accepts: p, br, b, i, em, h4 to h6, ul, ol and li.
func PlainText ¶
PlainText renders Markdown as plain text for stores that take no markup: paragraphs separated by blank lines, list items with bullets.
func PrintDPI ¶
PrintDPI is the resolution an image of the given pixels reaches when it fills a print area of the given inches, cropped to cover it.
func SVGSize ¶ added in v0.1.12
SVGSize validates a self-contained SVG and returns its intrinsic dimensions.
func StoreCover ¶
StoreCover returns the cover as the RGB JPEG every store accepts: the source itself when it already is one under 5 MB, otherwise re-encoded. A re-encoded cover carries the hash of its source in a comment, so the cover published last time is reused while the source is unchanged: re-encoding takes a tenth of a second.
func ValidISBN ¶
ValidISBN reports whether s is an ISBN-13 with a correct check digit; hyphens and spaces are ignored.
Types ¶
type Built ¶
type Built struct {
EPUB []byte
Print []byte // one HTML document for printing the PDF
PrintAssets map[string][]byte // flat file names the print documents reference
TrimInches [2]float64
PrintCover string // flat name of the image for the printed front cover
CoverPixels [2]int // its size
// contains filtered or unexported fields
}
Built is the output of a book build.
func (Built) ChapterStarts ¶
ChapterStarts maps chapter numbers to the pages they start on, read from the outline of a PDF printed from Document: the chapters are its last top-level bookmarks. It returns nil when the outline does not fit.
func (Built) CoverDocument ¶
CoverDocument renders the full wrap of the paperback cover: back, spine and front side by side with bleed on every edge. The spine carries title and author when spineText is set; the back carries the listing's back cover text and, with a paperback ISBN, its barcode.
func (Built) Document ¶
func (b Built) Document(o PrintOptions) []byte
Document renders a print document: the downloadable PDF with zero options.
type Chapter ¶
type Chapter struct {
Status string `json:"status"`
N int `json:"n"`
Title string `json:"title"`
Job string `json:"job"`
Beats string `json:"-"`
Words int `json:"words"`
File string `json:"file"` // relative to the book folder, e.g. chapters/01-start.md
Line int `json:"-"`
Exists bool `json:"written"`
}
Chapter is one planned chapter.
type Config ¶
type Config struct {
Kind string `json:"kind"`
Author string `json:"author"`
Language string `json:"language"`
Path string `json:"path"`
Offer string `json:"offer"`
Formats []string `json:"formats"`
Publisher string `json:"publisher"` // seller.name
Imprint string `json:"imprint"` // seller.imprint
Paper string `json:"paper"`
ISBNEbook string `json:"isbnEbook"`
ISBNPaperback string `json:"isbnPaperback"`
Sell string `json:"sell"` // page (default), shops or bundle
}
Config is deliverables.book in lfm.json.
type Listing ¶
type Listing struct {
Present bool
Description string // Markdown
Short string
BackCover string
Author string
Keywords []string
Tags []string
BISAC []string // "CODE label"
Thema []string
KDP []string
Ebook []Price
Paperback []Price
AIText string
AIImages string
AITools string
AIStatement string
}
Listing is the parsed listing.md.
func (Listing) AIGenerated ¶
AIGenerated reports whether any part of the book is AI-generated.
type Plan ¶
type Plan struct {
Kind string
Cast []string
POV, Tense string
Matter []Matter
CoverOpen bool
Name string // working name from the title line
Title string
Subtitle string
Chapters []Chapter
Images []Image
Cover string // book-relative path of the cover image
Trim string
Body string // font stack
Headings string
Accent string
Use, Avoid []string
UseLines []int // the concept line of each Use phrase
Text string // the concept as written, for names it declares
Objections []Objection
LookLine int
Description string // the promise, as the EPUB description
}
Plan is what the concept decided, as the compiler uses it.
type PrintOptions ¶
type PrintOptions struct {
Paper bool // the paperback interior: no cover and no links, mirrored margins
Inside float64 // inside margin of the paperback in inches
Pages map[int]int // chapter number -> page, printed in the contents
Blanks map[int]bool // chapter number -> a blank page comes before it
PadEnd int // blank pages at the end
}
PrintOptions shape a print document beyond the downloadable PDF.
type Printed ¶
type Printed struct {
PDF []byte // the downloadable PDF, with bookmarks and links
Interior []byte // the paperback interior
InteriorPages int // its page count, even
Inside float64 // its inside margin in inches
Wraps map[string][]byte // full cover wraps by spine formula: "kdp", "lulu"
Spines map[string]float64
Problems []string // what could not be printed, and why
Pending bool // the book changed since the last release printed it
LastCover []byte // the store cover of the last publish, reused when its source is unchanged
}
Printed holds what Chrome printed for the store packages.
type Report ¶
type Report struct {
Diagnostics []diagnostic.Diagnostic
Summary Summary
Plan Plan
Config Config
Sources map[string][]byte // book-relative path -> bytes of every chapter, image and style read
Listing Listing
EPUBImages map[string][]byte // optional PNG renditions, keyed by original SVG path
Previewable bool
Buildable bool // config valid and every chapter written; the build may run
}
Report is the result of checking the book.
func Check ¶
func Check(p project.Project, cfg Config, configured bool, offers map[string]*Price, site string, voices *research.Voices, competitors *research.Competitors) Report
Check reads the book of the project. configured tells whether lfm.json has deliverables.book; site is the page URL the download path hangs off.
type SourceError ¶ added in v0.1.12
SourceError locates a build failure in the author's input.
func (*SourceError) Error ¶ added in v0.1.12
func (e *SourceError) Error() string
func (*SourceError) Unwrap ¶ added in v0.1.12
func (e *SourceError) Unwrap() error
type Summary ¶
type Summary struct {
Kind string `json:"kind"`
Blocker string `json:"blocker,omitempty"`
Preview string `json:"preview,omitempty"`
Concept bool `json:"concept"`
Title string `json:"name,omitempty"`
Chapters []Chapter `json:"chapters,omitempty"`
Planned int `json:"planned"`
Written int `json:"written"`
Words int `json:"words"`
Target int `json:"targetWords"`
Complete bool `json:"complete"`
URL string `json:"url,omitempty"`
Sizes map[string]int `json:"fileBytes,omitempty"`
Files []string `json:"files,omitempty"` // built formats, set by the build
Listing bool `json:"listing"`
Pending bool `json:"pending"` // the paperback waits for a release to print
Layout string `json:"layout,omitempty"` // release: "fits", or the number of layout findings
Channels []string `json:"channels,omitempty"` // store packages written to distribution/
Sell string `json:"sell"` // page, shops or bundle
}
Summary describes the book for the report, the next step and --json.
type Wording ¶
type Wording struct {
Contents, Rights, CoverOf, Start, Copyright, Chapter string
DownloadTitle, Thanks, Writing, Download, Keep string
EPUBNote, PDFNote string
Accessible string // the EPUB's accessibility summary
}
Wording holds the few texts lfm writes into a book and its download page, per language; English is the fallback.