Template Syntax
Caspian's authored syntax is split across two runtimes: Jinja renders on the server, and PulsePoint enhances the final HTML in the browser. Caspian's current syntax contract is HTML-first.
Server-Side Jinja
Use native Jinja in authored route, layout, and component HTML whenever the value is known on the server. That includes text interpolation, attribute values, and normal control flow.
<h1>Welcome, {{ user.name }}</h1> <div class="{{ 'hidden' if not is_visible else 'block' }}"> Server-visible content </div> {% if user.is_admin %} <p>Admin tools</p> {% else %} <p>Standard dashboard</p> {% endif %} {% for post in posts %} <article>{{ post.title }}</article> {% endfor %}
page(),
layout(),
metadata, auth state, or other server-prepared context. In current
authored templates, Jinja blocks are the default control-flow syntax.
Browser-Side PulsePoint
Use PulsePoint when the browser owns the value after first render. That means interactive text, event handlers, list updates, refs, effects, and RPC-driven UI state.
<section> <h2>title</h2> <p>Count: count</p> <button onclick="setCount(count + 1)"> Increment </button> <template pp-for="item in items"> <div key="{item.id}">item.label</div> </template> <script> const title, items = [] = pp.props; const [count, setCount] = pp.state(0); </script> </section>
Use PulsePoint for
- Inline events such as
onclick,oninput, andonsubmit. pp.state(...),pp.effect(...),pp.ref(...), andpp.rpc(...).- Client-owned template expressions like
{count}and list rendering withpp-for.
Hard invariant
Author a plain <script>
inside the single root. Do not handwrite
pp-component
or type="text/pp".
Caspian injects those at render time.
Choose The Right Syntax
{{ user.name }}
{% if user.is_admin %}
{% for item in items %}
count onclick="save()" pp-for="item in items"
Native HTML Attributes
In authored route and layout HTML, prefer normal HTML attribute names:
class, for,
data-*, aria-*,
and lowercase event attributes like onclick.
| Preferred in authored HTML | Avoid teaching as the default |
|---|---|
| class="card" | className="card" |
| for="email" | htmlFor="email" |
| data-test-id="save-button" | dataTestId="save-button" |
| onclick="save()" | onClick="save()" |