CaTeX logo

CaTeX on Pub CaTeX Flutter web demo

CaTeX is a Flutter package that outputs TeX equations (like LaTeX, KaTeX, MathJax, etc.) inline using a widget and Flutter only - no plugins, no web views.

About CaTeX

Being Dart only, CaTeX renders TeX faster than any other Flutter plugin and is way more flexible. You can view a demo running on the web.

CaTeX is an open source project with the aim of providing a way to render TeX fast in Flutter. This was needed for the simpleclub app, hence, the association. It is also maintained by simpleclub (see the LICENSE file), initially created individually by creativecreatorormaybenot.

Note

CaTeX is pre-v0.1 release and lacks support for some major TeX functionality. You can help and contribute; see the contributing guide.

To benefit from the library right now, we fall back to an alternative when a specific formula is not supported. CaTeX automatically throws appropriate exceptions for handling this.

Usage

In order to manually input TeX equations to CaTeX you should use raw Dart strings (r'<input>' or '''<input>'''):

Widget build(BuildContext context) => CaTeX(r'\epsilon = \frac 2 {3 + 2}');

If you fetch the strings from a database, you can just pass them to CaTeX:

CaTeX(equation);

Unsupported input

If your input is currently not yet supported by CaTeX, you will see proper exceptions thrown for this. See the "Exception handling" section for more on this.

Please create a GitHub issue when you encounter such a case and it is either a bug or a missing feature. You can find issue templates when creating a new issue.

Controlling the font size

You will notice that the CaTeX widget does not have any parameters for styling (for the sake of simplicity). Instead, it uses inherited widgets to grab necessary properties.

The base font size of the rendered output is controlled via Flutter's DefaultTextStyle widget, i.e. the TextStyle.fontSize property.

Widget build(BuildContext context) {
  return DefaultTextStyle.merge(
    style: TextStyle(
      fontSize: 42,
    ),
    child: CaTeX(r'\CaTeX'),
  );
}

Implementation

The implementation is mainly based on The TeXbook by Donald E. Knuth, TeX by Topic by Victor Eijkhout, and the KaTeX JavaScript project.

Remember that CaTeX uses Flutter only! Consequently, all parsing and rendering is done in Dart.

The package basically uses two trees from input to displaying all nodes:

  1. Parsing tree, which consists of nodes storing only information about separation, i.e. the current mode (math or text) and the input for a given node.
    Each node in this tree will have the necessary information to create a render object from itself for the rendering tree.
  2. Rendering tree, which makes use of Flutter's render objects and takes care of sizing and rendering (using a canvas).

Fonts & licenses

The included fonts are taken from the katex-fonts repository and licensed under the SIL Open Font License.
Additionally, some code, e.g. what is used for translating symbols is from KaTeX.
You can find the license for the main KaTeX repo here.

Exception handling

There are three types of exceptions that are commonly thrown by CaTeX:

  1. ParsingException, which will be thrown if CaTeX does not understand your input, i.e. even before it tries to display your input. This will commonly occur when something about your input is wrong, e.g. the wrong number of arguments for a function.
    This type of exception will be shown on the screen by the default CaTeX widget (like a normal Flutter error).
  2. ConfigurationException, which will be thrown when CaTeX fails to display your input, i.e. when something about your input is not quite right (from CaTeX's point of view). Commonly, this means that something is not configured right, e.g. the name of a symbol.
    This type of exception will also be shown on the screen by the default CaTeX widget (like a normal Flutter error).
  3. RenderingException, which will only be thrown when the constraints given to CaTeX to render your input are not sufficient for your input.
    This type of exception is not shown on screen. Instead, CaTeX will only clip the output. However, you can still see the exception reported by Flutter during performLayout() in the logs.

If you want to customize the look of how ParsingExceptions and ConfigurationExceptions are displayed, consider overriding ErrorWidget.builder. If you want to see CaTeX errors in release mode, you will have to override the builder and ensure that any CaTeXException is handled differently than normal. An example override might look like this:

void main() {
  ErrorWidget.builder = (FlutterErrorDetails details) {
    final exception = details.exception;
    if (exception is CaTeXException) {
      return ErrorWidget(exception);
    }

    var message = '';
    // The assert ensures that any exceptions that are not CaTeX exceptions
    // are not shown in release and profile mode. This ensures that no
    // stack traces or other sensitive information (information that the user
    // is in no way interested in) is shown on screen.
    assert(() {
      message = '${details.exception}\n'
          'See also: https://flutter.dev/docs/testing/errors';
      return true;
    }());

    return ErrorWidget.withDetails(
      message: message,
      error: exception is FlutterError ? exception : null,
    );
  };
  runApp(const App());
}

See the example app for more examples.

Expanding supported functionality

This package is far from complete in terms of supporting all TeX functionality.
If you want support for more functions, symbols, macros, etc., we appreciate your contribution!
Please refer to the contributing guide to understand how you can easily add functions and more.

To aid our own prioritization for this project, we conducted some research examining how often particular TeX commands appear in some of simpleclub's content. This should give a rough feeling for what is most commonly used. A CSV file with the list of used functions and the frequency of appearance is maintained in the repo.

Mission

There are already a couple of TeX Flutter plugins out there. So why create another?

Most of those libraries use already existing implementations in other languages, mostly using web views and JavaScript.
This is a valid approach; it is straightforward to implement. You only have to write a wrapper.

However, we believe that utilizing web views is an overhead that makes the applications less portable and performant.
At simpleclub, we recently decided to move from a Flutter-native hybrid to going all-in with Flutter. Now, we need a well-written Flutter TeX library that works on every platform and can display lots of formulas. So we decided to start this open source effort of bringing Dart-native TeX support to Flutter.

A custom TeX parser could potentially also allow us to provide accessibility and screen reader support out of the box.
Here we could build on the work of T.V. Raman, who developed Audio System For Technical Readings (AsTeR) for his PhD.

As this involves a lot of work, we would be happy to work together with the open source for bringing this vision to life together - so everyone can benefit from a pure-Flutter TeX library.

See our contributing guide for more information.

Libraries

catex