Template Syntax Reference
Complete guide to ScribeEngine .stpl file syntax.
Route Declaration
Basic Routes
@route('/') # GET request (default)
@route('/about') # Static path
@route('/api/data') # Nested path
HTTP Methods
@route('/login', methods=['GET', 'POST'])
@route('/api/users', methods=['GET', 'POST', 'PUT', 'DELETE'])
Route Parameters
@route('/posts/<int:post_id>') # Integer
@route('/users/<username>') # String (default)
@route('/files/<path:filepath>') # Path (includes slashes)
@route('/product/<uuid:product_id>') # UUID
Python Blocks
Execute Python code with {$ ... $}:
{$
# Variables
title = "Hello"
items = [1, 2, 3]
# Loops
for item in items:
process(item)
# Conditionals
if user_id:
user = db['default'].find('users', user_id)
# Functions
def format_date(date):
return date.strftime('%Y-%m-%d')
$}
Available Objects
request- Flask request object (form data, headers, method)session- Flask session (dict-like)db- Database connectionsflash()- Flash messagesredirect()- Redirect to URLabort()- Return HTTP errorjsonify()- Return JSON response
Jinja2 Templates
Variables
<h1>{{ page_title }}</h1>
<p>{{ user.name }}</p>
<p>{{ items[0] }}</p>
Filters
{{ name | upper }} # UPPERCASE
{{ long_text | truncate(100) }} # Limit length
{{ date | default('No date') }} # Default value
Conditionals
{% if user %}
<p>Welcome, {{ user.name }}!</p>
{% else %}
<p>Please log in.</p>
{% endif %}
Loops
{% for post in posts %}
<h2>{{ post.title }}</h2>
{% endfor %}
{% for key, value in dict.items() %}
<p>{{ key }}: {{ value }}</p>
{% endfor %}
Decorators
@require_auth
Require login:
@route('/dashboard')
@require_auth
{$ ... $}
Redirects to /login if not authenticated.
@no_layout
Disable the automatic base.stpl wrapper. Useful for HTMX fragments or AJAX responses.
@route('/api/fragment')
@no_layout
{$ ... $}
<div>I am a bare HTML snippet</div>
@sse
Enable Server-Sent Events (SSE). This decorator:
- Sets the response mimetype to
text/event-stream. - Automatically applies
@no_layout. - Supports
yieldfor streaming updates.
@route('/counter')
@sse
{$
import time
for i in range(5):
count = i
yield frame() # Renders the template below
time.sleep(1)
$}
<div class="update">Current count: {{ count }}</div>
Built-in Helpers
frame(template=None, event=None, **kwargs)
Used within @sse routes to render fragments for the stream.
- template: Optional override for the template to render. Defaults to the route's own template.
- event: Optional SSE event name (e.g.,
event: update). - kwargs: Extra variables to pass to the template.
yield frame(event='notification', msg='New Alert!')
Return Statements
Redirect
{$
if not user:
return redirect('/login')
$}
JSON Response
{$
data = {"status": "success", "count": 42}
return jsonify(data)
$}
Abort (HTTP Error)
{$
if not authorized:
return abort(403) # Forbidden
$}
Layout Inheritance
Use base.stpl automatically:
@route('/page')
{$
page_title = "My Page" # Sets <title>
$}
<!-- Content automatically wrapped in base.stpl -->
<h1>Hello!</h1>