Skip to content

Commit e9b1dcd

Browse files
committed
Regenerate examples
1 parent 94a74a0 commit e9b1dcd

2 files changed

Lines changed: 210 additions & 0 deletions

File tree

regen.py

Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
import os, re
2+
3+
base_cpp = "/home/pep/Projects/processing-cpp.github.io/assets/examples/Basics"
4+
base_js = "/home/pep/Projects/processing-cpp.github.io/assets/examples_js/Basics"
5+
categories = sorted(os.listdir(base_cpp))
6+
7+
def strip_comment(code):
8+
code = code.strip()
9+
if code.startswith("/**"):
10+
end = code.find("*/")
11+
if end != -1:
12+
code = code[end+2:].strip()
13+
return code
14+
15+
def get_canvas_size(js_code):
16+
m = re.search(r'createCanvas\s*\(\s*(\d+)\s*,\s*(\d+)', js_code)
17+
if m: return int(m.group(1)), int(m.group(2))
18+
m = re.search(r'\bsize\s*\(\s*(\d+)\s*,\s*(\d+)', js_code)
19+
if m: return int(m.group(1)), int(m.group(2))
20+
return 640, 360
21+
22+
data = {}
23+
for cat in categories:
24+
cat_path = os.path.join(base_cpp, cat)
25+
if not os.path.isdir(cat_path): continue
26+
data[cat] = []
27+
for example in sorted(os.listdir(cat_path)):
28+
ex_path = os.path.join(cat_path, example)
29+
if not os.path.isdir(ex_path): continue
30+
pde = os.path.join(ex_path, example + ".pde")
31+
if not os.path.exists(pde): continue
32+
with open(pde) as f:
33+
code = f.read()
34+
js_file = os.path.join(base_js, cat, example, example + ".js")
35+
js_code = ""
36+
w, h = 640, 360
37+
if os.path.exists(js_file):
38+
with open(js_file) as f:
39+
js_code = strip_comment(f.read())
40+
w, h = get_canvas_size(js_code)
41+
slug = example.replace("_", "-").lower()
42+
data[cat].append({"id": cat+"_"+example, "name": example.replace("_"," "), "slug": slug, "code": code, "js": js_code, "w": w, "h": h})
43+
44+
def build_page_sidebar(active_id=""):
45+
s = '<div class="section-header" onclick="toggleSection(\'basics\')"><span>Basics</span><span class="arrow" id="basics-arrow">▾</span></div><div id="basics-section">'
46+
for cat, examples in data.items():
47+
s += f'<div class="category"><div class="category-title">{cat.replace("_"," ").title()}</div>'
48+
for ex in examples:
49+
active = 'class="active"' if ex["id"] == active_id else ""
50+
s += f'<a href="{ex["slug"]}.html" {active}>{ex["name"]}</a>'
51+
s += '</div>'
52+
s += '</div><div class="section-header" onclick="toggleSection(\'topics\')"><span>Topics</span><span class="arrow" id="topics-arrow">▸</span></div><div id="topics-section" style="display:none"><div class="category"><div class="category-title" style="color:#ccc;">Coming soon</div></div></div>'
53+
return s
54+
55+
shared_css = '''* { margin: 0; padding: 0; box-sizing: border-box; }
56+
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; color: #111; background: #fff; }
57+
a { color: #111; text-decoration: none; }
58+
nav { border-bottom: 1px solid #e0e0e0; padding: 0 2rem; display: flex; align-items: center; justify-content: space-between; height: 60px; position: sticky; top: 0; background: #fff; z-index: 100; }
59+
.nav-logo { display: flex; align-items: center; gap: 10px; color: #111; }
60+
.nav-logo img { width: 28px; height: 28px; }
61+
.nav-logo span { font-size: 15px; font-weight: 500; }
62+
.hamburger { background: none; border: none; cursor: pointer; font-size: 22px; padding: 4px 8px; display: none; }
63+
.layout { display: flex; min-height: calc(100vh - 60px); }
64+
.sidebar-outer { width: 220px; min-width: 220px; border-right: 1px solid #e0e0e0; display: flex; flex-direction: column; position: sticky; top: 60px; height: calc(100vh - 60px); }
65+
#site-sidebar { padding: 1.5rem 1.5rem 1rem; border-bottom: 1px solid #e0e0e0; display: flex; flex-direction: column; }
66+
#site-sidebar a { font-size: 14px; color: #555; padding: 0.4rem 0; display: block; }
67+
#site-sidebar a:hover { color: #111; }
68+
#site-sidebar a.active { color: #111; font-weight: 500; }
69+
.sidebar-examples { flex: 1; overflow-y: auto; }
70+
.section-header { display: flex; justify-content: space-between; align-items: center; padding: 0.85rem 1.5rem; font-size: 13px; font-weight: 600; color: #111; cursor: pointer; border-bottom: 1px solid #e0e0e0; user-select: none; }
71+
.section-header:hover { background: #f8f8f8; }
72+
.arrow { font-size: 11px; color: #aaa; }
73+
.category { margin-bottom: 0.25rem; }
74+
.category-title { font-size: 11px; font-weight: 600; color: #aaa; text-transform: uppercase; letter-spacing: 0.08em; padding: 0.75rem 1.5rem 0.25rem; }
75+
.category a { display: block; font-size: 13px; color: #555; padding: 0.3rem 1.5rem; }
76+
.category a:hover { color: #111; background: #f8f8f8; }
77+
.category a.active { color: #111; font-weight: 500; background: #f4f4f4; }
78+
.content { flex: 1; padding: 3rem 4rem; max-width: 900px; }
79+
.content h1 { font-size: 1.8rem; font-weight: 600; margin-bottom: 0.75rem; }
80+
.preview-wrap { border: 1px solid #e0e0e0; border-radius: 8px; overflow: hidden; margin-bottom: 2rem; display: inline-block; }
81+
.preview-wrap iframe { display: block; border: none; }
82+
.code-block { background: #f8f8f8; border-radius: 8px; overflow: hidden; }
83+
.code-header { padding: 0.75rem 1.25rem; border-bottom: 1px solid #e0e0e0; font-size: 12px; color: #888; font-family: monospace; display: flex; align-items: center; justify-content: space-between; }
84+
.copy-btn { font-size: 12px; color: #555; background: #fff; border: 1px solid #ddd; border-radius: 4px; padding: 3px 10px; cursor: pointer; font-family: inherit; }
85+
.copy-btn:hover { background: #f0f0f0; }
86+
.copy-btn.copied { color: #090; border-color: #090; }
87+
pre { padding: 1.5rem; font-family: "SF Mono","Fira Code",monospace; font-size: 13px; line-height: 1.7; overflow-x: auto; white-space: pre; }
88+
.welcome h1 { font-size: 1.8rem; font-weight: 600; margin-bottom: 1rem; }
89+
.welcome p { color: #555; line-height: 1.8; max-width: 500px; }
90+
footer { border-top: 1px solid #e0e0e0; padding: 2rem; text-align: center; font-size: 13px; color: #888; }
91+
@media (max-width: 768px) {
92+
.hamburger { display: block; }
93+
.sidebar-outer { position: fixed; top: 60px; left: -240px; width: 240px; height: calc(100vh - 60px); background: #fff; z-index: 200; transition: left 0.25s ease; box-shadow: 2px 0 12px rgba(0,0,0,0.08); }
94+
.sidebar-outer.open { left: 0; }
95+
.content { padding: 2rem 1.25rem; }
96+
.preview-wrap { max-width: 100%; }
97+
.preview-wrap iframe { max-width: 100%; }
98+
pre { font-size: 12px; }
99+
}'''
100+
101+
shared_js = '''function copyCode() {
102+
navigator.clipboard.writeText(document.getElementById('code-pre').innerText).then(() => {
103+
const btn = document.querySelector('.copy-btn');
104+
btn.textContent = 'Copied!'; btn.classList.add('copied');
105+
setTimeout(() => { btn.textContent = 'Copy'; btn.classList.remove('copied'); }, 2000);
106+
});
107+
}
108+
function toggleSection(name) {
109+
const sec = document.getElementById(name+'-section');
110+
const arrow = document.getElementById(name+'-arrow');
111+
const open = sec.style.display !== 'none';
112+
sec.style.display = open ? 'none' : 'block';
113+
arrow.textContent = open ? '▸' : '▾';
114+
}'''
115+
116+
def make_iframe(js_code, w, h):
117+
safe = js_code.replace('</script>', '<\\/script>').replace('`','\\`')
118+
return f'''<div class="preview-wrap"><iframe id="sketch-frame" width="{w}" height="{h}"></iframe></div>
119+
<script>(function(){{const iframe=document.getElementById('sketch-frame');const doc=iframe.contentDocument||iframe.contentWindow.document;doc.open();doc.write(`<!DOCTYPE html><html><head><style>*{{margin:0;padding:0;}}body{{overflow:hidden;}}</style><script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.9.0/p5.min.js"><\\/script></head><body><script>{safe}<\\/script></body></html>`);doc.close();}})();</script>'''
120+
121+
out_dir = "/home/pep/Projects/processing-cpp.github.io/examples"
122+
for fname in os.listdir(out_dir):
123+
if fname != "index.html":
124+
os.remove(os.path.join(out_dir, fname))
125+
126+
for cat, examples in data.items():
127+
for ex in examples:
128+
escaped = ex["code"].replace("&","&amp;").replace("<","&lt;").replace(">","&gt;")
129+
has_js = bool(ex["js"].strip())
130+
preview = make_iframe(ex["js"], ex["w"], ex["h"]) if has_js else ""
131+
page = f'''<!DOCTYPE html>
132+
<html lang="en">
133+
<head>
134+
<meta charset="UTF-8">
135+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
136+
<title>{ex["name"]} - C++ Mode Examples</title>
137+
<style>{shared_css}</style>
138+
</head>
139+
<body>
140+
<nav id="site-nav">
141+
<a href="../" class="nav-logo"><img src="../assets/cpp-logo.png" alt="C++ Mode"><span>C++ Mode</span></a>
142+
<button class="hamburger" onclick="document.querySelector('.sidebar-outer').classList.toggle('open')">☰</button>
143+
</nav>
144+
<div class="layout">
145+
<div class="sidebar-outer">
146+
<div id="site-sidebar">
147+
<a href="../libraries">Libraries</a>
148+
<a href="../reference">Reference</a>
149+
<a href="../examples">Examples</a>
150+
<a href="../about">About</a>
151+
</div>
152+
<div class="sidebar-examples">{build_page_sidebar(ex["id"])}</div>
153+
</div>
154+
<div class="content">
155+
<h1>{ex["name"]}</h1>
156+
{preview}
157+
<div class="code-block">
158+
<div class="code-header">
159+
<span>{ex["name"].lower().replace(" ","-")}.pde</span>
160+
<button class="copy-btn" onclick="copyCode()">Copy</button>
161+
</div>
162+
<pre id="code-pre">{escaped}</pre>
163+
</div>
164+
</div>
165+
</div>
166+
<footer><p>C++ Mode for Processing</p></footer>
167+
<script>{shared_js}</script>
168+
<script src="../assets/nav.js"></script>
169+
</body>
170+
</html>'''
171+
with open(os.path.join(out_dir, ex["slug"]+".html"),"w") as f:
172+
f.write(page)
173+
174+
ex_sidebar = build_page_sidebar()
175+
with open(os.path.join(out_dir,"index.html"),"w") as f:
176+
f.write(f'''<!DOCTYPE html>
177+
<html lang="en">
178+
<head>
179+
<meta charset="UTF-8">
180+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
181+
<title>Examples - C++ Mode for Processing</title>
182+
<style>{shared_css}</style>
183+
</head>
184+
<body>
185+
<nav id="site-nav">
186+
<a href="/" class="nav-logo"><img src="../assets/cpp-logo.png" alt="C++ Mode"><span>C++ Mode</span></a>
187+
<button class="hamburger" onclick="document.querySelector('.sidebar-outer').classList.toggle('open')">☰</button>
188+
</nav>
189+
<div class="layout">
190+
<div class="sidebar-outer">
191+
<div id="site-sidebar">
192+
<a href="../libraries">Libraries</a>
193+
<a href="../reference">Reference</a>
194+
<a href="../examples" class="active">Examples</a>
195+
<a href="../about">About</a>
196+
</div>
197+
<div class="sidebar-examples">{ex_sidebar}</div>
198+
</div>
199+
<div class="content"><div class="welcome"><h1>Examples</h1><p>Short programs exploring the basics of creative coding with C++ Mode. Select an example from the left.</p></div></div>
200+
</div>
201+
<footer><p>C++ Mode for Processing</p></footer>
202+
<script>{shared_js}</script>
203+
<script src="../assets/nav.js"></script>
204+
</body>
205+
</html>''')
206+
207+
print(f"done — {sum(len(v) for v in data.values())} examples generated")

regen.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#!/bin/bash
2+
cd ~/Projects/processing-cpp.github.io
3+
python3 regen.py && git add . && git commit -m "Regenerate examples" && git push origin main

0 commit comments

Comments
 (0)