{"apiVersion":"v1","name":"Crate.tools catalog","description":"Every tool Crate publishes. Tools run in the visitor's browser; this API describes them and points at the page that executes them.","documentation":"https://crate.tools/developers/","openapi":"https://crate.tools/openapi.json","count":50,"tools":[{"slug":"pdf-page-size","name":"PDF page size","description":"Find out what size the pages really are, in millimetres, inches, and points.","category":"pdf","keywords":["pdf page size","check pdf dimensions","is my pdf a4","pdf page dimensions","what size is this pdf","pdf paper size checker"],"url":"https://crate.tools/tools/pdf-page-size/","self":"https://crate.tools/api/v1/tools/pdf-page-size.json","processing":"client-only","limits":"Measures the crop box with the page's rotation applied — what a reader shows and a printer images — and names the full sheet and the trim box beside it when they differ. A page is called by a paper name only within a third of a millimetre; within 3 mm it is reported as near that size with the gap stated; beyond that it is a custom size. Reads the page geometry of password-protected files, though nothing can be extracted from them. Up to 100 MB."},{"slug":"video-to-gif","name":"Video to GIF","description":"Turn a few seconds of a clip into an animated GIF, with the size shown before you make it.","category":"video","keywords":["video to gif","mp4 to gif","convert video to gif","make a gif from a video","webm to gif","gif maker"],"url":"https://crate.tools/tools/video-to-gif/","self":"https://crate.tools/api/v1/tools/video-to-gif.json","processing":"client-only","limits":"Up to 60 frames in one animation, which is 6 seconds at 10 frames a second or 12 at 5. The frame count multiplied by the frame size has to stay under 20 megapixels. GIF holds 256 colours per frame and stores delays in hundredths of a second, so a frame rate like 15 fps really plays at 14.3 — the page says which. There is no sound in a GIF. Frames are read by seeking the video your browser already plays, so any file it can play works, and one it cannot is refused with the codec named."},{"slug":"images-to-gif","name":"Images to GIF","description":"Turn a set of still images into an animated GIF, in the order you choose.","category":"images","keywords":["images to gif","png to gif","jpg to gif","make a gif from pictures","animated gif maker","photos to gif"],"url":"https://crate.tools/tools/images-to-gif/","self":"https://crate.tools/api/v1/tools/images-to-gif.json","processing":"client-only","limits":"Two to 60 images per animation, and the frame count multiplied by the frame size has to stay under 20 megapixels, so a long animation has to be smaller on each side. Every frame gets its own 256-colour palette, which is the most GIF can hold. Transparency is one bit per pixel — a pixel is see-through or it is not — so soft anti-aliased edges come out hard unless you fill them with a colour. Every frame shares one delay; per-frame timing is not adjustable here. An animated file used as an input contributes only its first frame."},{"slug":"gif-to-frames","name":"GIF to frames","description":"Split an animated GIF, WebP, AVIF, or APNG into numbered still images.","category":"images","keywords":["gif to frames","gif frame extractor","split gif into images","animated webp to png"],"url":"https://crate.tools/tools/gif-to-frames/","self":"https://crate.tools/api/v1/tools/gif-to-frames.json","processing":"client-only","limits":"Up to 30 MB and 600 saved frames per run; take every few frames for a longer animation. Frame extraction needs the browser's ImageDecoder, which Chrome and Edge 94+ have and Safari and Firefox do not yet — the page says so rather than failing silently. JPEG cannot store transparency, so see-through areas are filled with the chosen colour. A still image is reported as a single frame rather than refused."},{"slug":"markdown-to-html","name":"Markdown to HTML","description":"Turn Markdown into clean HTML you can paste into a template.","category":"text","keywords":["markdown to html","md to html","convert markdown","markdown converter","readme to html","markdown preview"],"url":"https://crate.tools/tools/markdown-to-html/","self":"https://crate.tools/api/v1/tools/markdown-to-html.json","processing":"client-only","limits":"CommonMark's common core plus GitHub tables, task lists and strikethrough. Footnotes, definition lists, front matter, math blocks and emoji shortcodes are not converted. Raw HTML is escaped by default. A javascript: or data:text/html link destination is dropped rather than written into the output. The preview runs with no scripts and no network access, so images from the web show as broken in it."},{"slug":"strip-html-tags","name":"Strip HTML tags","description":"Get the readable text out of HTML, with its paragraphs and lists intact.","category":"text","keywords":["strip html tags","remove html tags","html to text","html tag remover"],"url":"https://crate.tools/tools/strip-html-tags/","self":"https://crate.tools/api/v1/tools/strip-html-tags.json","processing":"client-only","limits":"Up to 200,000 characters. The markup is read as text, not parsed as a document, so malformed or half-copied HTML is handled on a best-effort basis. Script, style, noscript, template, svg, and head contents are removed entirely. &nbsp; becomes an ordinary space rather than a no-break space. Table cells are separated by tabs, which is not a layout. Nothing in the input is ever executed, fetched, or rendered."},{"slug":"text-extract-emails","name":"Extract email addresses","description":"Pull every email address out of pasted text, deduplicated and ready to paste.","category":"text","keywords":["extract email addresses","find emails in text","email extractor","get emails from text"],"url":"https://crate.tools/tools/text-extract-emails/","self":"https://crate.tools/api/v1/tools/text-extract-emails.json","processing":"client-only","limits":"Up to 200,000 characters. Addresses are recognised by their shape, not verified — a listed address can still bounce, and nothing is sent to check. The domain must contain a dot, so name@localhost and other intranet-only addresses are not matched. Addresses deliberately obscured as \"name at example dot com\" are not decoded. A Retina asset name such as logo@2x.png is address-shaped and will be listed."},{"slug":"lorem-ipsum","name":"Lorem ipsum generator","description":"Generate placeholder text by paragraph, sentence, or exact word count.","category":"text","keywords":["lorem ipsum generator","placeholder text","dummy text","filler text"],"url":"https://crate.tools/tools/lorem-ipsum/","self":"https://crate.tools/api/v1/tools/lorem-ipsum.json","processing":"client-only","limits":"Up to 200 paragraphs, 500 sentences, or 2,000 words per generation. The vocabulary is the conventional Latin word list, so the text is not real Latin and carries no meaning. HTML output wraps paragraphs in <p> tags only; it adds no headings, lists, links, or attributes."},{"slug":"text-line-ending-converter","name":"Line ending converter","description":"Convert LF, CRLF, or CR line endings and download exact UTF-8 text.","category":"text","keywords":["line ending converter","CRLF to LF","LF to CRLF","Unix Windows newlines"],"url":"https://crate.tools/tools/text-line-ending-converter/","self":"https://crate.tools/api/v1/tools/text-line-ending-converter.json","processing":"client-only","limits":"Up to 200,000 characters; imported files up to 800 KB. UTF-8 only, with an existing UTF-8 BOM preserved. NUL characters and invalid UTF-8 files are rejected. Pasting or editing may normalize original endings to LF. Unicode NEL, line separator, and paragraph separator are preserved. No final newline is added or removed."},{"slug":"whitespace-visualizer","name":"Whitespace visualizer","description":"See the tabs, odd spaces, and line endings hiding in your text.","category":"text","keywords":["show whitespace","visualize tabs and spaces","find hidden characters","show line endings"],"url":"https://crate.tools/tools/whitespace-visualizer/","self":"https://crate.tools/api/v1/tools/whitespace-visualizer.json","processing":"client-only","limits":"Up to 200,000 characters. The output is the marked text, not your original — copying it copies the markers, which is the point, but means it is not a way to clean the text up. Tabs are shown as a single arrow rather than expanded to a tab stop, so this does not show the column alignment an editor would. Browser textareas normalise pasted line endings to LF, so the Windows marker usually appears only on text supplied through the agent input."},{"slug":"smart-quotes-converter","name":"Smart quotes converter","description":"Swap straight quotes for typographic ones, or strip them back out.","category":"text","keywords":["smart quotes","curly quotes","straight quotes","typographic apostrophe"],"url":"https://crate.tools/tools/smart-quotes-converter/","self":"https://crate.tools/api/v1/tools/smart-quotes-converter.json","processing":"client-only","limits":"Up to 200,000 characters. Which mark belongs where is decided from the neighbouring characters, which is right for prose and wrong inside code — converting a snippet to curly quotes will break it, so convert code the other way. A quote after a number is usually feet, inches, or minutes; those need the prime marks ′ and ″, which this does not insert, but it counts them and says so. Nested single quotes inside double quotes are handled; the reverse convention is not detected."},{"slug":"text-remove-accents","name":"Remove accents","description":"Turn accented text into plain letters, without pretending it is lossless.","category":"text","keywords":["remove accents","remove diacritics","convert to ascii","unaccent text"],"url":"https://crate.tools/tools/text-remove-accents/","self":"https://crate.tools/api/v1/tools/text-remove-accents.json","processing":"client-only","limits":"Up to 200,000 characters. This is a Latin-script operation: Cyrillic, Greek, Arabic, and East Asian text passes through unchanged, and the workspace says how many letters that affected. Removing accents loses information — Polish ł and ż, Turkish ı, and Vietnamese tone marks all distinguish real words — so the result is for systems that cannot take the original, not a replacement for it. Some letters become two, so the text gets longer."},{"slug":"text-character-frequency","name":"Character frequency","description":"Count every character, including the ones you cannot see.","category":"text","keywords":["character frequency","letter frequency","count characters","find hidden characters"],"url":"https://crate.tools/tools/text-character-frequency/","self":"https://crate.tools/api/v1/tools/text-character-frequency.json","processing":"client-only","limits":"Up to 200,000 characters. Characters are counted as a reader sees them, so an emoji made of several code points, or a letter followed by a combining accent, counts once — which means the total here can be lower than a raw character count. Percentages are each character's share of what was counted, so they change when you switch between letters only and everything. Names for invisible characters are English labels, and anything without a printable form is shown as its U+ code point."},{"slug":"text-reading-time","name":"Reading time calculator","description":"How long a text takes to read — at a pace you choose.","category":"text","keywords":["reading time","words per minute","speech length","how long to read"],"url":"https://crate.tools/tools/text-reading-time/","self":"https://crate.tools/api/v1/tools/text-reading-time.json","processing":"client-only","limits":"Up to 200,000 characters. This is an estimate from a word count and a pace: it cannot know your material's difficulty, your pauses, a demo in the middle of a talk, or how long a reader spends on a diagram. Words are counted with the browser's Unicode segmentation, so the number matches the Word counter exactly. Pace is a whole number between 30 and 1,000 words a minute, and targets run from 1 to 600 minutes."},{"slug":"longest-line","name":"Longest line finder","description":"Find which lines are too long, and by how much.","category":"text","keywords":["longest line","line length checker","find long lines","character count per line"],"url":"https://crate.tools/tools/longest-line/","self":"https://crate.tools/api/v1/tools/longest-line.json","processing":"client-only","limits":"Up to 200,000 characters. Every line is measured including blank ones, and a trailing newline ends the last line rather than adding an empty one. Characters are counted as a reader counts them, so an emoji made of several code points is one character — but four or more bytes, which is why the unit is a choice. Tabs count as one character regardless of how wide they are displayed, so this does not measure the visual column position."},{"slug":"text-frequency","name":"Word frequency counter","description":"See which words a text actually leans on, and how often.","category":"text","keywords":["word frequency","word count by word","most used words","keyword density"],"url":"https://crate.tools/tools/text-frequency/","self":"https://crate.tools/api/v1/tools/text-frequency.json","processing":"client-only","limits":"Up to 200,000 characters. Words are found using the browser's Unicode word segmentation, so an apostrophe stays inside its word and hyphenated words count once; languages written without spaces are segmented by the browser's own rules. The skipped list is English only and deliberately short. Counting is by exact word, not by meaning: run and running, or a singular and its plural, are different words here."},{"slug":"text-column-extractor","name":"Extract text columns","description":"Pull one or more columns out of pasted rows, quotes and all.","category":"text","keywords":["extract column","get csv column","split columns","cut fields from text"],"url":"https://crate.tools/tools/text-column-extractor/","self":"https://crate.tools/api/v1/tools/text-column-extractor.json","processing":"client-only","limits":"Up to 200,000 characters and 500 selected columns. Columns are counted from 1, left to right, per row: a row with fewer columns yields an empty value in that position rather than borrowing from the next row. There is no header row concept, so a header is simply the first row and is extracted like any other. Quoted values are understood when splitting on a separator; splitting on runs of whitespace has no quoting convention and treats every gap as a boundary."},{"slug":"text-prefix-suffix","name":"Add prefix and suffix","description":"Wrap every line in the same text, ready for SQL, JSON, or Markdown.","category":"text","keywords":["add prefix to each line","add suffix","wrap lines in quotes","prepend text to lines"],"url":"https://crate.tools/tools/text-prefix-suffix/","self":"https://crate.tools/api/v1/tools/text-prefix-suffix.json","processing":"client-only","limits":"Up to 200,000 characters, with 5,000 characters in each of the prefix and suffix. Text is added exactly as typed, with no space inserted for you and no escaping of what is already on the line — a value containing a quote is not escaped when you wrap it in quotes. Dropping the last line's separator removes one trailing comma, semicolon, pipe, or ampersand from the suffix, not the whole suffix. A trailing newline ends the last line rather than creating a blank one."},{"slug":"reverse-text","name":"Reverse text","description":"Reverse characters, words, or line order without breaking emoji.","category":"text","keywords":["reverse text","backwards text","reverse string","reverse word order"],"url":"https://crate.tools/tools/reverse-text/","self":"https://crate.tools/api/v1/tools/reverse-text.json","processing":"client-only","limits":"Up to 200,000 characters. Characters and word order are reversed within each line, so line breaks stay where they are; reversing line order leaves each line's contents untouched. Reversing right-to-left text changes the stored order rather than mirroring what you see on screen, and the workspace says so. Grouping emoji and accents correctly needs a browser with Intl.Segmenter; without it a warning appears because some characters can come apart."},{"slug":"shuffle-lines","name":"Shuffle lines","description":"Put a list in a random order you can reproduce later.","category":"text","keywords":["shuffle lines","randomize list","random order","shuffle list"],"url":"https://crate.tools/tools/shuffle-lines/","self":"https://crate.tools/api/v1/tools/shuffle-lines.json","processing":"client-only","limits":"Up to 200,000 characters. Randomness comes from a seeded generator, not from the cryptographic random source, so this is meant for ordering a list rather than for anything security-related such as generating keys or lottery draws. Blank lines are dropped when shuffling lines, and act as separators when shuffling paragraphs. With a short list, landing back on the original order is ordinary chance and is pointed out rather than hidden."},{"slug":"compare-lists","name":"Compare lists","description":"See what two lists share, and what only one of them has.","category":"text","keywords":["compare lists","list difference","find missing items","intersection of two lists"],"url":"https://crate.tools/tools/compare-lists/","self":"https://crate.tools/api/v1/tools/compare-lists.json","processing":"client-only","limits":"Up to 200,000 characters per list. Values are compared as whole lines, so a line that differs by anything other than case or edge spacing under loose matching is a different value; there is no fuzzy or partial matching. A value repeated inside one list is compared and shown once, and the number of repeats is reported. Blank lines are ignored. Which list is A and which is B matters — only in A and only in B are different answers."},{"slug":"list-to-csv","name":"List to CSV","description":"Turn a pasted list into correctly quoted CSV a spreadsheet can read.","category":"text","keywords":["list to csv","csv generator","comma separated values","quote csv values"],"url":"https://crate.tools/tools/list-to-csv/","self":"https://crate.tools/api/v1/tools/list-to-csv.json","processing":"client-only","limits":"Up to 200,000 characters. This produces a single column, or a single row — it does not build a multi-column table from one paste, and it adds no header row. Values are quoted only when the format requires it. Nothing is written to a file, so if you paste the result into a text editor and save it as .csv, add a byte-order mark yourself when Excel needs to be told the file is UTF-8. Blank lines are skipped rather than becoming empty records."},{"slug":"text-to-list","name":"Text to list","description":"Turn lines or a comma-separated string into a bullet or HTML list.","category":"text","keywords":["text to list","comma separated to list","bullet list generator","text to html list"],"url":"https://crate.tools/tools/text-to-list/","self":"https://crate.tools/api/v1/tools/text-to-list.json","processing":"client-only","limits":"Up to 200,000 characters. A line break always ends an item, so an item cannot span two lines. Nested or indented lists are not produced — every item is at the same level. Quoted values are only honoured when splitting on a separator, not when splitting on lines, and doubled quotes inside a quoted value become one. Blank items are skipped and counted rather than becoming empty bullets."},{"slug":"text-to-slug","name":"Text to slug","description":"Turn a heading into a clean URL segment, or a whole list at once.","category":"text","keywords":["text to slug","slug generator","url slug","permalink from title"],"url":"https://crate.tools/tools/text-to-slug/","self":"https://crate.tools/api/v1/tools/text-to-slug.json","processing":"client-only","limits":"Up to 200,000 characters. Output is always lowercase, since a slug that differs only by capitals is a different URL on most servers. Latin letters only transliterates what it can — ü to u, ß to ss, ø to o — and drops anything with no Latin equivalent, so a Cyrillic or Japanese heading can come back empty; the count of dropped letters is shown. Slugs are not truncated to a maximum length, and nothing is renamed to resolve a repeat."},{"slug":"find-replace-text","name":"Find and replace text","description":"Swap every occurrence of a word or phrase, with a marked preview.","category":"text","keywords":["find and replace","replace text","search and replace","bulk replace"],"url":"https://crate.tools/tools/find-replace-text/","self":"https://crate.tools/api/v1/tools/find-replace-text.json","processing":"client-only","limits":"Up to 200,000 characters, with 5,000 characters in each of the find and replace fields. Matching is plain text only: there are no regular expressions, capture groups, or wildcards, and every character including . * $ ( is searched for literally. The fields are single-line, so a search term cannot span a line break. Replacements are made in one pass over your original, so a replacement containing the search term is never matched again."},{"slug":"remove-line-numbers","name":"Remove line numbers","description":"Strip the numbering off a pasted list or a copied code gutter.","category":"text","keywords":["remove line numbers","strip numbering","delete line numbers","copy code without line numbers"],"url":"https://crate.tools/tools/remove-line-numbers/","self":"https://crate.tools/api/v1/tools/remove-line-numbers.json","processing":"client-only","limits":"Up to 200,000 characters. Only a number at the start of a line is considered, and it must be followed by whitespace, so 1.1 outline numbering and a sentence beginning with a year stay intact. Bullets such as - or • are not numbering and are left alone. In the default mode nothing is stripped unless every leading number is one more than the previous one; the line where the count breaks is named instead."},{"slug":"add-line-numbers","name":"Add line numbers","description":"Number a pasted list or snippet, starting wherever you need.","category":"text","keywords":["add line numbers","number lines","numbered list","line numbering"],"url":"https://crate.tools/tools/add-line-numbers/","self":"https://crate.tools/api/v1/tools/add-line-numbers.json","processing":"client-only","limits":"Up to 200,000 characters, and numbering must stay under 1,000,000. Numbers follow the order you pasted; nothing is sorted or renumbered by content. Existing numbering is not detected and removed — lines that already start with a number get a second one and are counted for you. A trailing newline ends the last line rather than adding an extra numbered line."},{"slug":"remove-line-breaks","name":"Remove line breaks","description":"Join hard-wrapped lines back into flowing text or one line.","category":"text","keywords":["remove line breaks","join lines","unwrap text","text to one line"],"url":"https://crate.tools/tools/remove-line-breaks/","self":"https://crate.tools/api/v1/tools/remove-line-breaks.json","processing":"client-only","limits":"Up to 200,000 characters. Whitespace at each joined line's edges is removed with the break, so indentation inside a paragraph does not survive; blank lines are kept exactly as pasted when paragraphs are kept. A word split across a break keeps its hyphen and is reported rather than silently repaired. Joining everything into one line drops blank lines and the final newline."},{"slug":"remove-empty-lines","name":"Remove empty lines","description":"Delete blank lines from a list, or close up the extra ones.","category":"text","keywords":["remove empty lines","delete blank lines","remove blank lines","remove extra line breaks"],"url":"https://crate.tools/tools/remove-empty-lines/","self":"https://crate.tools/api/v1/tools/remove-empty-lines.json","processing":"client-only","limits":"Up to 200,000 characters. Lines are never reordered, joined, or deduplicated, and indentation inside kept lines is untouched. A line holding only a zero-width space is not whitespace, so it is kept and reported rather than removed. CRLF, CR, LF, and Unicode line separators are preserved as supplied, and a final newline is kept."},{"slug":"trim-whitespace","name":"Trim whitespace","description":"Clean up line edges while keeping the spaces inside your text.","category":"text","keywords":["trim whitespace","remove trailing spaces","trim lines","remove leading spaces"],"url":"https://crate.tools/tools/trim-whitespace/","self":"https://crate.tools/api/v1/tools/trim-whitespace.json","processing":"client-only","limits":"Up to 200,000 characters. Trimming applies to each line, not just the outside of the whole document. Internal spaces, tabs, blank lines, duplicates, and line order stay intact. Unicode whitespace such as non-breaking spaces is removed at selected edges; zero-width spaces are not. Both ends removes indentation and trailing Markdown spaces."},{"slug":"sort-lines","name":"Sort lines","description":"Sort a list alphabetically, numerically, or in natural order.","category":"text","keywords":["sort lines","alphabetize list","natural sort","numeric order"],"url":"https://crate.tools/tools/sort-lines/","self":"https://crate.tools/api/v1/tools/sort-lines.json","processing":"client-only","limits":"Up to 10,000 lines and 200,000 characters. Blank lines move to the end in either direction. Duplicates and original spacing are preserved; line endings become LF. Numeric mode accepts signed numbers with dot decimals, without grouping commas, units, or exponents. Text comparison ignores case and surrounding whitespace."},{"slug":"jpg-to-png","name":"JPG to PNG","description":"Convert a JPG image to a crisp, lossless PNG.","category":"images","keywords":["jpg","jpeg","png","converter"],"url":"https://crate.tools/tools/jpg-to-png/","self":"https://crate.tools/api/v1/tools/jpg-to-png.json","processing":"client-only","limits":"The output is often larger than the original JPEG. Conversion cannot remove a background or restore lost detail."},{"slug":"png-to-jpg","name":"PNG to JPG","description":"Turn a PNG into a smaller, easy-to-share JPG.","category":"images","keywords":["png","jpeg","jpg","converter"],"url":"https://crate.tools/tools/png-to-jpg/","self":"https://crate.tools/api/v1/tools/png-to-jpg.json","processing":"client-only","limits":"JPEG does not support transparency. Transparent pixels are flattened onto the fill colour you choose, which defaults to white, and lower quality can introduce visible artifacts. Animated PNGs keep only their first frame."},{"slug":"webp-to-png","name":"WebP to PNG","description":"Make a WebP image work wherever PNG does.","category":"images","keywords":["webp","png","converter"],"url":"https://crate.tools/tools/webp-to-png/","self":"https://crate.tools/api/v1/tools/webp-to-png.json","processing":"client-only","limits":"Animated WebP is flattened to the first decoded frame; the tool detects this and says so before you download. Use a dedicated animation tool to preserve motion."},{"slug":"image-resizer","name":"Image resizer","description":"Get the right dimensions. Keep the right proportions.","category":"images","keywords":["resize","image","pixels","dimensions","width","height","aspect ratio"],"url":"https://crate.tools/tools/image-resizer/","self":"https://crate.tools/api/v1/tools/image-resizer.json","processing":"client-only","limits":"Resizing does not crop. With the ratio unlocked you can set width and height independently, which stretches the picture. Enlarging cannot invent additional detail, and the tool warns when you ask for it. Output is limited to 40 million pixels."},{"slug":"image-compressor","name":"Image compressor","description":"Make image files lighter with adjustable JPEG quality.","category":"images","keywords":["compress","jpg","jpeg","image","reduce","size"],"url":"https://crate.tools/tools/image-compressor/","self":"https://crate.tools/api/v1/tools/image-compressor.json","processing":"client-only","limits":"Output is JPEG, with transparent areas filled by the colour you choose. A smaller result is not guaranteed for already optimized images. No exact target file size is promised."},{"slug":"extract-first-pdf-page","name":"Extract first PDF page","description":"Save one page of a PDF as its own file.","category":"pdf","keywords":["pdf","first","page","extract","save"],"url":"https://crate.tools/tools/extract-first-pdf-page/","self":"https://crate.tools/api/v1/tools/extract-first-pdf-page.json","processing":"client-only","limits":"Password-protected or malformed PDFs are not supported, and the tool says so before you try. Digital signatures are not preserved as valid signatures in a newly written document."},{"slug":"extract-last-pdf-page","name":"Extract last PDF page","description":"Save the closing page, or the last few, as their own PDF.","category":"pdf","keywords":["extract last pdf page","last page of pdf","save final page","pdf closing page","signature page"],"url":"https://crate.tools/tools/extract-last-pdf-page/","self":"https://crate.tools/api/v1/tools/extract-last-pdf-page.json","processing":"client-only","limits":"Pages are copied rather than re-rendered, so text stays selectable. Taking every page produces a copy of the whole document rather than an extract. Password-protected or damaged PDFs are refused before you try. A digital signature on the closing page does not remain a valid signature in a newly written file."},{"slug":"merge-pdf","name":"Merge PDF","description":"Bring multiple PDFs together in the order you choose.","category":"pdf","keywords":["combine","merge","pdf","files"],"url":"https://crate.tools/tools/merge-pdf/","self":"https://crate.tools/api/v1/tools/merge-pdf.json","processing":"client-only","limits":"Files are processed in memory with a 100 MB combined input limit and a 30 file cap. Password-protected or damaged files are flagged by name and must be removed. Interactive forms, bookmarks, and signatures may not survive page copying."},{"slug":"rotate-pdf","name":"Rotate PDF","description":"Turn every page the right way up.","category":"pdf","keywords":["rotate","pdf","pages","orientation"],"url":"https://crate.tools/tools/rotate-pdf/","self":"https://crate.tools/api/v1/tools/rotate-pdf.json","processing":"client-only","limits":"The selected angle applies to every page. This version does not offer individual page selection. Signed documents will be rewritten."},{"slug":"word-counter","name":"Word counter","description":"Count words, characters, and reading time as you type.","category":"text","keywords":["word","character","counter","reading","time"],"url":"https://crate.tools/tools/word-counter/","self":"https://crate.tools/api/v1/tools/word-counter.json","processing":"client-only","limits":"Reading time assumes 200 words per minute. Sentence counts are punctuation-based estimates; character counts use Unicode code points, not visible grapheme clusters."},{"slug":"word-diff","name":"Word diff","description":"See exactly what changed between two pieces of text.","category":"text","keywords":["compare","text","word","difference","diff"],"url":"https://crate.tools/tools/word-diff/","self":"https://crate.tools/api/v1/tools/word-diff.json","processing":"client-only","limits":"Inputs are limited to 20,000 characters each to keep comparisons responsive. Word-level comparison is intended for prose, not semantic source-code analysis."},{"slug":"case-converter","name":"Case converter","description":"Switch between UPPERCASE, lowercase, Title Case, and Sentence case.","category":"text","keywords":["text","case","uppercase","lowercase","title"],"url":"https://crate.tools/tools/case-converter/","self":"https://crate.tools/api/v1/tools/case-converter.json","processing":"client-only","limits":"Title case capitalizes every word start; it does not implement a publication-specific style guide, keep small words lowercase, or infer proper nouns. Sentence case lowercases the rest of each sentence, so acronyms are not preserved."},{"slug":"remove-duplicate-lines","name":"Remove duplicate lines","description":"Clean up a list while keeping its original order.","category":"text","keywords":["deduplicate","lines","remove","repeated","text"],"url":"https://crate.tools/tools/remove-duplicate-lines/","self":"https://crate.tools/api/v1/tools/remove-duplicate-lines.json","processing":"client-only","limits":"Exact matching is case-sensitive and preserves whitespace; the loose mode compares entries trimmed and lowercased but keeps the first spelling it saw. Blank lines are treated as entries, and only the first blank line is retained."},{"slug":"json-formatter","name":"JSON formatter","description":"Format, validate, and make sense of your JSON.","category":"developer","keywords":["json","beautifier","formatter","validator"],"url":"https://crate.tools/tools/json-formatter/","self":"https://crate.tools/api/v1/tools/json-formatter.json","processing":"client-only","limits":"Standard JSON only: comments and trailing commas are rejected. Duplicate object keys resolve to the last value. Large numeric literals may lose precision through JavaScript number parsing."},{"slug":"base64-encode-decode","name":"Base64 encode / decode","description":"Encode UTF-8 text or decode Base64 back to text.","category":"developer","keywords":["base64","encode","decode","utf8"],"url":"https://crate.tools/tools/base64-encode-decode/","self":"https://crate.tools/api/v1/tools/base64-encode-decode.json","processing":"client-only","limits":"This tool handles UTF-8 text, not arbitrary binary downloads. Invalid Base64 or invalid UTF-8 returns an error. Encoding always produces the standard padded alphabet; decoding also accepts URL-safe and unpadded input."},{"slug":"url-encode-decode","name":"URL encode / decode","description":"Escape a value, or a whole address, and back again.","category":"developer","keywords":["url","encode","decode","percent","encoding"],"url":"https://crate.tools/tools/url-encode-decode/","self":"https://crate.tools/api/v1/tools/url-encode-decode.json","processing":"client-only","limits":"One value uses encodeURIComponent; whole URL uses encodeURI, which leaves reserved punctuation alone and cannot repair an already broken address. Decoding always uses decodeURIComponent. Plus signs are not treated as spaces. Malformed percent escapes return an error."},{"slug":"sha256-hash","name":"SHA-256 hash","description":"Generate a SHA-256 fingerprint of your text.","category":"developer","keywords":["sha256","hash","generator","checksum"],"url":"https://crate.tools/tools/sha256-hash/","self":"https://crate.tools/api/v1/tools/sha256-hash.json","processing":"client-only","limits":"Whitespace and line endings affect the result. A plain SHA-256 digest is not a password storage scheme. Web Crypto requires HTTPS or localhost."},{"slug":"video-first-frame","name":"Video frame extractor","description":"Save the first decoded video frame as a PNG.","category":"video","keywords":["video","first","frame","extract","thumbnail","png"],"url":"https://crate.tools/tools/video-first-frame/","self":"https://crate.tools/api/v1/tools/video-first-frame.json","processing":"client-only","limits":"Codec support depends on your browser and operating system. A black opening frame remains black. The captured initial frame is not a guarantee of frame-exact editing."},{"slug":"video-trim","name":"Video trimmer","description":"Cut a clip out of a video, frame by frame, in your browser.","category":"video","keywords":["video trimmer","trim video","cut video","mp4 cutter","shorten video","clip video"],"url":"https://crate.tools/tools/video-trim/","self":"https://crate.tools/api/v1/tools/video-trim.json","processing":"client-only","limits":"Reads MP4-family containers; WebM and Matroska are not read here. An exact cut re-encodes the picture once and needs a browser with an H.264 encoder, and is limited to 9,000 frames a run; a keyframe cut copies any length instantly but starts at the nearest keyframe. Audio is copied rather than re-encoded, so it starts on its own frame boundary. Up to 100 MB."}]}