Our own tool: a pricing engine, quote builder and sales CRM for print businesses, built first for our own studio. Print quotes depend on paper, ink, imposition, setup fees, markup and VAT, and most shops manage that in spreadsheets, so underquoting eats margin. We built a single guided workflow that prices a job, sends a polished quote by email and tracks it through the pipeline, with no running cost.Accurate pricing, polished quotes, and full sales pipeline visibility, with zero infrastructure cost.
Read it your way.You are reading the plain-English version. Flip to Technical for how it is built.You are reading the technical version: architecture, integrations and engineering detail.
Price it. Quote it. Win it.Price it.Quote it.Win it.Price it.Quote it.Win it.Price it.Quote it.Win it.Price it.Quote it.Win it.
Cyan
100%
Magenta
100%
Yellow
100%
Key
100%
Our own pricing engine, quote builder and sales pipeline for print shops. A job is priced and quoted in about two minutes, it costs nothing a month to run, and every client record stays on your own computer.
A fully client-side Next.js 16 app: a pure pricing function over a pre-configured rate card, React Hook Form and Zod on every input, Zustand persisted to localStorage, HTML quote emails through Resend, shipped as a static export with no backend.
Running cost
£0/mo
Quote turnaround
~2 min
Client data privacy
100%
Sales pipeline stages
5
01 / The brief
Plate Key
Eight variables. One price.
Pricing print looks simple until you try it. One quote depends on the paper, its weight, the ink, what your printer can take, how many fit on a sheet, the setup, your markup and VAT. Most shops juggle all that in spreadsheets and gut feel, and every slip comes straight off the margin.Print pricing is deceptively complex. A single quote depends on paper type, weight, ink costs, printer capabilities, imposition layouts, setup fees, markup strategy, and VAT, variables that most print shops manage through spreadsheets, gut feel, or outdated software. Quoting errors eat directly into margins. Manual follow-ups fall through the cracks. Most off-the-shelf solutions demand monthly subscriptions, cloud accounts, and onboarding overhead that small print businesses neither need nor want.
Var 01
Paper type
Silk, gloss, kraft or pearl
stock.perM2 × sheet m²
Var 02
Weight
Will it even go through the printer?
stock.gsm ∈ printer.gsm
Var 03
Ink
Draft, standard or high quality
INK_PER_M2[quality] × sides
Var 04
Printer
Which machine can run the job
printerFor(size, stock)
Var 05
Imposition
How many fit on one sheet
⌊aw ÷ iw⌋ × ⌊ah ÷ ih⌋, both ways round
Var 06
Setup
Getting the press ready, plus spoiled sheets
printer.makeReady + overs
Var 07
Markup
Your margin, set per product
cost × markup[product]
Var 08
VAT
20%, or zero for leaflets
net × vat[product]
Before: the spreadsheet
fx=ROUND((B4*C9)+D2*1.2,2)
B4Prices worked out in spreadsheets and by gut feel
C9Every underquote comes straight off the margin
D2Follow-ups fall through the cracks
E7Monthly subscriptions, cloud accounts and onboarding
F1#REF!
After: one docket
One guided flow prices the job, line by line
Imposition and ink costed every time, so no more underquoting
Every quote tracked through five stages to payment
Nothing to pay monthly and nothing to sign up to
02 / Price a job
Plate Cyan
Every penny shows its working.
Pick a product, a size and a paper, set the quantity and the finish, and the price builds itself line by line: paper, ink, setup, finishing, your margin and VAT. It even knows when a paper is too heavy for the printer. Try it. These are sample rates, but the sums are the real ones.Each control dispatches a partial job into a reducer that normalises it (valid size, finish and quantity for the product, and a stock some printer accepts at that size) and passes it to a pure priceJob(). Imposition tries both orientations with bleed and gripper; overs add a fixed make-ready allowance plus 2% running waste; money is integer pence end to end.
Product
Size
Paper stock
Quantity
250 business cards
12.1p each
1002505001k2.5k5k
Printed sides
Print quality
Finish
12.1p each / 250 business cards
£30.35
Job docket
No. Q-0412
Sample rates
250 business cards, Standard 85 × 55 mm, 350gsm silk, double sided
Standard print / Digital press
Paper
£2.27
Ink
£1.04
Setup
£10.00
Finishing
£0.00
Margin 90%
£11.98
VAT 20%
£5.06
Total inc VAT
£30.35
12.1p each / 250 business cards
Up on sheet
21
SRA3
15 sheets
Inc. overs
3
Price each, by quantity
Quote follows this job
Sample rates for illustration. The real app ships with real paper stocks, printers and products set up, and every rate is the shop's own to change.
The pricing function (simplified)
type Job = {
product: ProductId; size: SizeId; stock: StockId;
qty: number; sides: 1 | 2;
quality: 'draft' | 'standard' | 'high';
finish: FinishId;
};
type PriceResult =
| { ok: true; parts: Record<Segment, Pence>; total: Pence;
printer: Printer; layout: Imposition; sheets: number }
| { ok: false; reason: string }; // e.g. 350gsm will not feed
// Pure: no I/O, no clock, no network. Rates come from the
// pre-configured rate card; whole pence throughout.
export function priceJob(job: Job): PriceResult;
Recalculated 0 times this visit / 0 network requests / no loading state
Change anything and the price is worked out again before your finger leaves the button. Nothing is sent anywhere to do it: the sums happen right here on the page, the same way they do in the shop's app.
03 / Send the quote
Plate Magenta
One click from price to inbox.
The job you just priced is already a quote. Add a name and an email, write a short note, and it goes out looking like it came from a proper print shop, with a matching version ready to print or save. Add more jobs from the docket and they become extra lines on the same quote.Quotes are assembled line by line from priced jobs, validated with React Hook Form and a Zod schema, and rendered as an HTML email delivered through Resend, with a PDF-ready layout built from the same line data. Below: the schema, the template and the exact payload this form would hand to the email service.
From
Your Print Shop <quotes@print-shop.example>
To
Ailsa Grant <ailsa@example.com>
Subject
Your print quote Q-0412: £30.35 inc VAT
Your Print ShopQ-0412
Hi Ailsa,
Thanks for getting in touch. Here is the price we talked about, printed here in Glasgow.
Quote lines
Item
Net
01250 business cards, Standard 85 × 55 mm, 350gsm silk, double sided
£25.29
Net
£25.29
VAT
£5.06
Total
£30.35
Accept this quoteValid for 30 days
Sample client and rates. The real app sends this as a formatted email, with a matching PDF-ready layout for offline sharing.
Quote form: React Hook Form + Zod (simplified)
const quoteForm = z.object({
name: z.string().trim().min(2, 'Add the client’s name'),
email: z.string().trim().email('Enter a valid email address'),
note: z.string().max(280).optional(),
validDays: z.union([z.literal(14), z.literal(30)]),
});
const form = useForm<QuoteForm>({ resolver: zodResolver(quoteForm) });
Quote email template (simplified)
export function QuoteEmail({ quote, shop }: Props) {
return (
<Html><Preview>{quote.ref}: {gbp(quote.total)} inc VAT</Preview>
<Body style={paper}>
<Letterhead shop={shop} />
<Text>Hi {quote.client.name},</Text>
<Text>{quote.note}</Text>
<LineTable lines={quote.lines} /> {/* same rows as the PDF */}
<Totals net={quote.net} vat={quote.vat} total={quote.total} />
<Button href={acceptUrl(quote)}>Accept this quote</Button>
<Text>Valid for {quote.validDays} days.</Text>
</Body>
</Html>
);
}
Every job moves through the same five stages, from first enquiry to paid and done. Drag a card along, or use its arrows, and watch the totals change: what is in play, how many quotes you win, which deposits have come in and what is still owed. The quote you send above lands under Quoted.Deals move between enquiry, quoted, accepted, deposit paid and completed. Payment state is derived from the stage (nothing, a 50% deposit, or the full balance), and stage totals, win rate, average order and outstanding balance are computed from the deal list rather than stored, so they can never drift.
Posters, 25: 25 posters, A2 420 × 594 mm, 200gsm poster satin, single sided
£34.08
02 Quoted2
£98.64
Studio Ishbel
Business cards, 250: 250 business cards, Standard 85 × 55 mm, 300gsm pearlescent, double sided, soft-touch lamination
£59.17
Calum Reid Joinery
Business cards, 500: 500 business cards, Standard 85 × 55 mm, 400gsm uncoated board, double sided
£39.47
03 Accepted1
£155.94
Leaf & Loaf Café
Folded leaflets, 1,000: 1,000 folded leaflets, A4 flat 210 × 297 mm, 120gsm recycled uncoated, double sided, roll fold to dl
£155.94
Awaiting 50% deposit
04 Deposit paid1
£32.05
Glenview Running Club
Posters, 50: 50 posters, A3 297 × 420 mm, 170gsm gloss, single sided
£32.05
£16.03 paid / £16.02 due
05 Completed2
£266.42
Northside Florist
Business cards, 1,000: 1,000 business cards, Standard 85 × 55 mm, 300gsm kraft, double sided, round corners
£69.56
Hanna Lind Photography
Flyers, 2,500: 2,500 flyers, A6 105 × 148 mm, 350gsm silk, double sided, matt lamination
£196.86
Sample clients and jobs, invented for illustration and priced by the sample rates above. Deposits are taken at half the quote.
Pipeline store (simplified)
// A Zustand slice, persisted with the rest of the store
moveDeal: (id: DealId, to: StageId) =>
set((s) => ({
deals: s.deals.map((d) =>
d.id === id ? { ...d, stage: to, paid: paidAt(d, to) } : d
),
})),
// paidAt: nothing until Deposit paid, then 50%, then the lot.
// Derived, never stored: stage totals, win rate, outstanding.
const stats = useStore(useShallow((s) => pipelineStats(s.deals)));
05 / Your data stays here
Plate Key
It never leaves the building.
Most business software keeps your customers on someone else's computer and charges you every month for it. This keeps everything on yours. Flip the switch to see where a client's details usually travel, and what that costs.Fully client-side: Zustand with localStorage for state, a static export for delivery, no database, no backend and no auth surface. The same pattern runs on this page: your demo session is persisted to this browser and offered back on reload.
Your browser, on your computer
Kept here, and only here
Client records8
Quotes6
Pipeline stages5
Vendor’s cloud database: never receives your data
Vendor backups: never receives your data
Login provider: never receives your data
Product analytics: never receives your data
Your client’s inbox, when you send: your client data goes here
Monthly bill, two people
£0
No hosting, no database, no subscription
Over a year
£0
Runs from any web host
On this device, right now
Nothing yet. Price a job or move a card above and it is saved here, in this browser only. Reload the page and it will offer it back.
The subscription side is an illustration of the usual model, not a named product. The right-hand panel is real: this page saves your demo in your own browser and nowhere else.
There is no account to make and no password to forget. Your client list, quotes and pipeline sit on the computer you use, so they are yours, and the only thing that ever leaves is the quote you choose to email.
Persistence and export (simplified)
// The store
export const useStore = create<State>()(
persist(
(...a) => ({ ...pricingSlice(...a), ...quoteSlice(...a), ...pipelineSlice(...a) }),
{ name: 'print-calculator', storage: createJSONStorage(() => localStorage) }
)
);
// next.config.ts
export default { output: 'export' }; // plain HTML, CSS and JS: any host, no server
State lives in one Zustand store persisted to localStorage, so there is no database, no auth and no API to secure. The build is a static export: HTML, CSS and JS on any host, which is why the running cost is £0.
The only outbound call in normal use is the quote email through Resend. Pricing, quoting and the pipeline make no network requests at all, which is also why every recalculation is instant.
This demo reads its own save back through a version check and per-record validation in parseSession(): anything malformed is dropped, never trusted.
Results
£0/mo0/mo
Running cost
~2 min2 min
Quote turnaround
100%100%
Client data privacy
55
Sales pipeline stages
01Prices came out right from day one: the sheet layouts and ink costs are worked out every time, so each job is priced from its real costsQuoting accuracy improved immediately, imposition calculations and ink cost modelling eliminated the margin erosion caused by underquoting
02A quote that used to take hours of checking spreadsheets now takes a couple of minutes, step by stepQuote turnaround cut from hours to minutes, what previously required cross-referencing spreadsheets is now a guided workflow
03For the first time the whole sales picture is on one screen: how many quotes turn into jobs, which deposits are still owed, and what is coming inFull pipeline visibility for the first time, conversion rates, outstanding deposits, and revenue at a glance
04Nothing to pay to keep it running: no hosting bill, no database and no monthly subscriptionZero infrastructure cost, no database, no hosting backend, no recurring SaaS fees
05Useful from the first time it opens, already set up with real papers, printers and products, so there is nothing to learn firstProductive from the first launch, pre-configured with real industry defaults, zero onboarding required
Start a project like this
Need software built for your business?
We build software like this for clients too. Tell us what your business needs to run on, and we will come back with a fixed written quote after a short discovery call.
Studio: Unit 204b, 36-38 Washington Street, Glasgow G3 8AZ. Phone 0141 345 5841.
Spec sheet
The architecture, integrations, performance numbers and code standards behind this project live in the technical version, for whoever looks after your IT.
Spec Sheet
Accurate pricing, polished quotes, and full sales pipeline visibility, with zero infrastructure cost.
Architecture
Framework
Next.js 16 with React 19 and Turbopack
State & Persistence
Zustand with localStorage, fully client-side, zero backend
Forms
React Hook Form with Zod schema validation for every input
UI System
Radix UI primitives with Tailwind CSS and CVA variants
Deployment
Static export, runs on any hosting, no server required
Integrations
Email Delivery
Resend API for transactional quote emails with HTML templates
Pricing Data
Pre-configured paper stocks, printer profiles, and ink cost tables
VAT Calculation
UK VAT rates applied automatically with configurable exemptions
Performance
Data Privacy
100% client-side, all data stays on the device, never leaves the browser
Infrastructure Cost
£0/month, no database, no backend, no recurring SaaS fees
Startup Time
Productive from first launch, pre-configured with real industry defaults
Calculation Speed
Instant recalculation on every input change, no loading states
Code Quality
→TypeScript strict mode with noUncheckedIndexedAccess
→Zod validation on every form and calculation input
→Immutable state updates via Zustand
→Component-driven architecture with Radix UI primitives
→Accessible markup meeting WCAG 2.1 AA standards
→Zero runtime dependencies on external services for core functionality
Technologies
Next.js 16
TypeScript
Tailwind CSS
Radix UI
Zustand
React Hook Form
Zod
Resend
Questions about Print Calculator & CRM
What is Print Calculator & CRM?+
Our own tool: a pricing engine, quote builder and sales CRM for print businesses, built first for our own studio. Print quotes depend on paper, ink, imposition, setup fees, markup and VAT, and most shops manage that in spreadsheets, so underquoting eats margin. We built a single guided workflow that prices a job, sends a polished quote by email and tracks it through the pipeline, with no running cost.
How is it built, in plain terms?+
A self-contained web app that stores its data in the browser, so there is no server, no login and no monthly fee.
What does it do for a business?+
Quote turnaround cut from hours to roughly two minutes, at no running cost.
How long did the project take?+
6 weeks.
How much does bespoke software like this cost?+
Bespoke software projects start from £10,000. We reply with a fixed written quote after a short discovery call, so you know the price before any work starts.
Where is Glasgow GFX based?+
Our studio is at Unit 204b, 36-38 Washington Street, Glasgow G3 8AZ, and we work with businesses across the UK. Phone 0141 345 5841.
Next Project
Font Creator for Adobe Illustrator
A native Illustrator extension that eliminates the multi-tool font creation workflow, draw letterforms, assign glyphs, and export production-ready OpenType fonts without leaving the app.
Start a Project · Start a Project · Start a Project
Have a project?
Websites, web apps and bespoke software for businesses across the UK, built in Glasgow. Tell us what you need and we will come back with a fixed written quote after a discovery call.