Build Adobe Express
KINDAreplaces $9.99/mosaves $119.88/yrback to the verdict
A template renderer whose hard problems are producing the same pixels every time despite fonts and images loading asynchronously, fitting real text into a fixed box, and keeping a licence record for every asset that ends up in an export.
Before step 1
Everything below is assumed from the first step. Tick each one when you actually have it, not when you plan to.
- installfree
Why Runs the renderer and the batch command.
Get it nodejs.org, or your version manager. open ↗
Verify
node --version prints v22 or higher - installfree
Why The render is a screenshot of a real page, which is how you get text layout that is correct rather than approximated.
Get it Install the library and let it download its browser.
Verify
A blank page screenshots at an exact requested size - installfree for the permissive models; a commercial agreement for some others
Why The library is permissive but its models are not uniformly so, and the default one requires a paid agreement for commercial use.
Get it Install the library, read its model list and its licence notes, then choose a model and record why. open ↗
Verify
The chosen model name and its licence are in configuration before any cut-out is produced - have readyfree for open fonts; whatever the foundry charges otherwise
Why Rendering is unrestricted under an open font licence but the file itself travels with conditions, and a client font may be neither.
Get it Download the font files with their licence text and keep both in the repository.
Verify
Every font in the brand file has a licence recorded in the assets table - decidefree
Why Platform image specifications change and a size baked into a template is never revisited, so the date is part of the data.
Get it Look up the current published specification for each platform you export to and record the dimensions with the date.
Verify
Every size in configuration carries a checked date
Data model
Create these before the first phase that stores anything. Changing a table later is the expensive kind of change.
- templates(id, name, width, height, version, html_path, fields_json) · size is part of the identity, not a setting - brand(fonts_json, colours_json, logo_path, licence_notes) · one record, read by every render - assets(id, kind, path, sha256, source, licence_name, licence_url, commercial_ok, added_at) · kind is font, image or model - renders(id, template_id, template_version, field_values_json, asset_ids_json, output_path, rendered_at, duration_ms) - sidecars(render_id, json_path) · the file written beside every export so it can be reproduced - The assets table is the one that stops this being a tool that quietly puts a non-commercial model's output on a billboard.
Environment variables
These go in a .env file the app reads at startup. The pack's .env.example is this table as a file · copy it, never commit the filled-in version.
| Variable | Needed | Example | Where the value comes from |
|---|---|---|---|
TEMPLATE_DIR | required | ./templates | HTML and CSS templates. Each declares its own size. |
BRAND_FILE | required | ./brand.json | Fonts, colours and logo. The only place these are defined. |
OUTPUT_DIR | required | ~/Graphics | Exports and their sidecars, named predictably by date and template. |
CUTOUT_MODEL | required | a permissively licensed segmentation model name | Named explicitly. The library default is not permitted here. |
PROJECT_USE | required | commercial | Commercial or personal. A commercial project refuses non-commercial model weights. |
DEVICE_PIXEL_RATIO | required | 2 | Fixed, because it is part of what makes two renders identical. |
The build, in order
The same pixels every time
Rendering a template twice with the same values produces identical files.
The load event is not the same as ready to photograph.
Files
src/render.jstests/determinism.test.jsSize is part of the template identity.
Files
src/render.jsA silently wrong graphic is worse than no graphic.
Files
src/assets.js
done when · tick each as it passeswatch out- Screenshotting as soon as the page fires its load event catches the moment before the web font has been applied, so roughly one render in ten comes out in the fallback font with different line breaks, and it is never the one you look at. Wait for the font loading promise and for every image to report itself decoded, then screenshot.
One brand file that every template reads
Changing a colour or a font once changes every graphic on the next render.
One source for colour and type, read by every template.
Files
src/brand.jstemplates/_base.cssDrift starts with one exception nobody removed.
Files
tests/no-literals.test.jsThe old graphics are the ones that look wrong first.
Files
src/rerender.js
done when · tick each as it passeswatch out- Templates that carry their own colours drift within a month, because the third one was made by copying the second and then adjusted, and by the time anyone notices there are five nearly-identical blues and no way to find them. Have the render fail when a template declares a colour or font family directly, and keep the check in the suite.
Real text in a fixed box
A long headline and a short one both look deliberate.
Guessing from character count breaks on the first unusual string.
Files
src/fit.jstests/fit.test.jsUnreadably small is a failure, not a solution.
Files
templates/schema.jsonAll three appear in real names.
Files
tests/text-cases.test.js
done when · tick each as it passeswatch out- Choosing a font size from the number of characters works until somebody types a word that cannot be broken or a string of emoji, and then the headline either overflows the canvas silently or shrinks to something unreadable, and the export still succeeds. Measure the rendered text, honour a minimum size, and fail the render with the field name when the text cannot fit.
Cut-outs, and the licence that comes with them
Background removal runs locally with a model you chose on purpose and recorded.
The default is the one with the commercial restriction.
Files
config/models.jsonsrc/cutout.jsYou will be asked, possibly by a client's lawyer.
Files
src/assets.jssrc/sidecar.jsBetter a failed render than a licence problem.
Files
src/cutout.jstests/licence.test.js
done when · tick each as it passeswatch out- Installing the popular background removal library and calling it with defaults uses a model released for non-commercial use, so the first client logo you produce is built on weights you do not have a licence for, and nothing in the tooling tells you. Name the model in configuration, record its licence beside the output, and make the build refuse a model marked as non-commercial when the project is marked commercial.
Batches, sizes and a graphic you can rebuildproduct builder
One set of values produces every size you need, and any past graphic can be regenerated.
They change, and a constant in a template never gets rechecked.
Files
config/sizes.jsonThe sidecar is what makes a rebuild possible.
Files
src/sidecar.jsA rebuild that nobody has run is a hope about the future.
Files
src/rebuild.jstests/rebuild.test.js
done when · tick each as it passeswatch out- Hard-coding social image dimensions in the templates guarantees that a year later half the exports are the wrong size for the platform they were made for, and the only way to find out is to look at them one by one. Keep sizes in configuration with the date the platform's published specification was checked, and show that date in the batch output.
That is the whole plan for Adobe Express. What it deliberately does not cover is below · check the gaps before you call it a replacement.
- Stock photography and premium templates.
- Video and PDF editing.
- Generative image creation.
- A drag and drop canvas.
- Adobe Stock/assets
- PDF/video tooling
- brand kits
- Creative Cloud integration
- mobile apps
- licensing coverage
- A contact sheet of every template rendered with sample values, which catches brand drift at a glance
- A second brand file for a client, since everything already reads from one place
- Animated exports of the same templates, once the still renders have been stable for a month
Need the files? The project pack on the verdict page hands your agent the whole brief · more design.