use std::path::Path;
#[allow(dead_code)] const PHI: f64 = 1.618033988749895;
pub const DEFAULT_ADDRESS: &str = "φ:qttps://local.dreamwell";
pub const DEFAULT_WIDTH: u32 = 1920;
pub const DEFAULT_HEIGHT: u32 = 1080;
pub fn generate(project_dir: &Path, project_name: &str) -> Result<GeneratedProject, String> {
std::fs::create_dir_all(project_dir).map_err(|e| format!("create project dir: {e}"))?;
let tapestry_json = generate_tapestry_json(project_name);
std::fs::write(project_dir.join("tapestry.json"), &tapestry_json)
.map_err(|e| format!("write tapestry.json: {e}"))?;
let landing_content = generate_landing_page(project_name);
std::fs::write(project_dir.join("index.html"), &landing_content).map_err(|e| format!("write index.html: {e}"))?;
let server_config = generate_server_config(project_name);
std::fs::write(project_dir.join("server_tapestry.json"), &server_config)
.map_err(|e| format!("write server config: {e}"))?;
let readme = generate_readme(project_name);
std::fs::write(project_dir.join("README.md"), &readme).map_err(|e| format!("write README: {e}"))?;
let digest = blake3::hash(landing_content.as_bytes());
let digest_hex: String = digest.as_bytes().iter().map(|b| format!("{b:02x}")).collect();
Ok(GeneratedProject {
project_name: project_name.to_string(),
address: DEFAULT_ADDRESS.to_string(),
files_created: 4,
landing_digest_hex: digest_hex,
})
}
#[derive(Debug)]
pub struct GeneratedProject {
pub project_name: String,
pub address: String,
pub files_created: u32,
pub landing_digest_hex: String,
}
impl GeneratedProject {
pub fn display(&self) {
println!();
println!(" Dreamwell QTTPS v1.0.0 LTS");
println!();
println!(" Dreamwell Online.");
println!(" \u{03c6}:{}", self.address);
println!();
println!(" project {}", self.project_name);
println!(" files {}", self.files_created);
println!(" BLAKE3 {}...", &self.landing_digest_hex[..16]);
println!();
println!(" Next:");
println!(" dream init # Create identity");
println!(" dream pack index.html # Pack landing page");
println!(" dream portal open . # Share with peers");
println!(" dream signal open --name \"{}\" . # Broadcast", self.project_name);
println!();
}
}
fn generate_tapestry_json(name: &str) -> String {
format!(
r#"{{
"project": {{
"name": "{}",
"version": "1.0.0",
"engine_version": "1.0.0",
"entry_scene": "hello_universe",
"template": "hello-universe"
}},
"qttps": {{
"address": "{}",
"mode": "signal",
"port": 9618,
"auto_pack": true,
"phi_sync": true
}},
"render": {{
"width": {},
"height": {},
"fps": 60,
"render_path": "dreamwell",
"quality_preset": "balanced"
}},
"sdk": {{
"max_mutations_per_weave": 64,
"max_mutations_per_frame": 256,
"max_dreamlets": 4096,
"max_threads": 0,
"sacred_path_enabled": true
}},
"auth": {{
"signing_enabled": true,
"default_key": "default"
}}
}}"#,
name, DEFAULT_ADDRESS, DEFAULT_WIDTH, DEFAULT_HEIGHT
)
}
fn generate_landing_page(name: &str) -> String {
format!(
r#"<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width={}, initial-scale=1.0">
<title>{} — φ:qttps://local.dreamwell</title>
<style>
* {{ margin: 0; padding: 0; box-sizing: border-box; }}
body {{
background: #0a0a0f;
color: #e0e0e0;
font-family: 'SF Mono', 'Cascadia Code', 'JetBrains Mono', monospace;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-height: 100vh;
}}
.address-bar {{
position: fixed;
top: 0;
width: 100%;
padding: 12px 24px;
background: #1a1a2e;
border-bottom: 1px solid #2a2a3e;
display: flex;
align-items: center;
gap: 12px;
}}
.address-bar .phi {{ color: #f0c040; font-size: 18px; }}
.address-bar input {{
flex: 1;
background: #0a0a1e;
border: 1px solid #3a3a5e;
border-radius: 6px;
padding: 8px 16px;
color: #c0c0d0;
font-family: inherit;
font-size: 14px;
}}
.content {{
text-align: center;
padding: 120px 40px 40px;
}}
h1 {{
font-size: 72px;
font-weight: 200;
letter-spacing: -2px;
background: linear-gradient(135deg, #f0c040, #e07020);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
margin-bottom: 24px;
}}
.subtitle {{
font-size: 18px;
color: #808090;
margin-bottom: 48px;
}}
.phi-constant {{
font-size: 48px;
color: #f0c040;
opacity: 0.3;
margin-bottom: 32px;
}}
.commands {{
text-align: left;
background: #12121e;
border: 1px solid #2a2a3e;
border-radius: 8px;
padding: 24px 32px;
max-width: 600px;
margin: 0 auto;
}}
.commands code {{
display: block;
padding: 4px 0;
color: #80c0f0;
}}
.commands .comment {{ color: #505070; }}
</style>
</head>
<body>
<div class="address-bar">
<span class="phi">φ</span>
<input type="text" value="φ:qttps://local.dreamwell" readonly>
</div>
<div class="content">
<div class="phi-constant">φ</div>
<h1>Hello Universe!</h1>
<p class="subtitle">
Dreamwell Online. This page is a .dreamfile.<br>
BLAKE3 attested. φ-optimized. Clean Compute receipted.
</p>
<div class="commands">
<code><span class="comment"># Share this with peers</span></code>
<code>dream portal open .</code>
<code></code>
<code><span class="comment"># Broadcast publicly</span></code>
<code>dream signal open --name "{}" .</code>
<code></code>
<code><span class="comment"># Check your identity</span></code>
<code>dream identity --verify</code>
</div>
</div>
</body>
</html>"#,
DEFAULT_WIDTH, name, name
)
}
fn generate_server_config(name: &str) -> String {
format!(
r#"{{
"server": {{
"mode": "signal",
"port": 9618,
"name": "{}",
"address": "{}",
"max_connections": 256,
"shard_blade_enabled": true,
"auto_trust_management": true,
"inbox_quarantine": true,
"seal_interval_ticks": 1000,
"heartbeat_ms": 1618,
"idle_timeout_ms": 21034,
"proof_of_work": true
}},
"identity": {{
"auto_chain_advance": true,
"quantum_id_enabled": true,
"min_interactions": 21
}},
"limits": {{
"max_file_size_bytes": 1073741824,
"max_chunk_size_bytes": 65536,
"max_concurrent_relays": 64,
"max_sessions": 1024,
"max_channels": 1024,
"gate_closing_ticks": 7
}}
}}"#,
name, DEFAULT_ADDRESS
)
}
fn generate_readme(name: &str) -> String {
format!(
r#"# {} — A QTTPS Project
Created with `dream up --hello-universe`.
## Quick Start
```bash
dream init # Create identity
dream pack index.html # Pack landing page as .dreamfile
dream open index.html.dreamfile # Open it (verified, receipted)
dream portal open . # Share with peers
dream signal open --name "{}" . # Broadcast publicly
```
## Address
```
{}
```
## What This Is
A minimal QTTPS project with a landing page served at a φ-addressed quantum endpoint. The page is a `.dreamfile` — BLAKE3 attested, self-describing, and decodable by any QTTPS client without prior knowledge.
## Next Steps
- Edit `index.html` and re-pack with `dream pack index.html`
- Add files to the project folder and open a portal: `dream portal open .`
- Deploy as a signal for public access: `dream signal open --name "{}" .`
- Check the CLI reference: `dream --help` or see `DREAMWELL-CLI.md`
## Standards
- Clean Compute compliant (explicit, measurable, receipted)
- φ-derived constants throughout (1618ms heartbeat, 7-tick gate closing)
- Triple BLAKE3 verification (per-section + per-file + per-session)
- Zero-trust identity (hardware-bound .fibo)
"#,
name, name, DEFAULT_ADDRESS, name
)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn generate_creates_all_files() {
let dir = std::env::temp_dir().join("hello_universe_test");
let result = generate(&dir, "test-project").unwrap();
assert_eq!(result.files_created, 4);
assert!(dir.join("tapestry.json").exists());
assert!(dir.join("index.html").exists());
assert!(dir.join("server_tapestry.json").exists());
assert!(dir.join("README.md").exists());
assert_eq!(result.address, DEFAULT_ADDRESS);
assert!(!result.landing_digest_hex.is_empty());
let _ = std::fs::remove_dir_all(&dir);
}
#[test]
fn tapestry_json_is_valid() {
let dir = std::env::temp_dir().join("hello_universe_tapestry");
generate(&dir, "tapestry-test").unwrap();
let content = std::fs::read_to_string(dir.join("tapestry.json")).unwrap();
let parsed: serde_json::Value = serde_json::from_str(&content).unwrap();
assert_eq!(parsed["project"]["name"], "tapestry-test");
assert_eq!(parsed["project"]["template"], "hello-universe");
assert_eq!(parsed["qttps"]["address"], DEFAULT_ADDRESS);
assert_eq!(parsed["render"]["fps"], 60);
let _ = std::fs::remove_dir_all(&dir);
}
#[test]
fn landing_page_contains_phi_address() {
let dir = std::env::temp_dir().join("hello_universe_landing");
generate(&dir, "landing-test").unwrap();
let content = std::fs::read_to_string(dir.join("index.html")).unwrap();
assert!(content.contains("φ:qttps://local.dreamwell"));
assert!(content.contains("Hello Universe!"));
assert!(content.contains("dream portal open"));
assert!(content.contains("dream signal open"));
let _ = std::fs::remove_dir_all(&dir);
}
#[test]
fn server_config_has_phi_constants() {
let dir = std::env::temp_dir().join("hello_universe_server");
generate(&dir, "server-test").unwrap();
let content = std::fs::read_to_string(dir.join("server_tapestry.json")).unwrap();
let parsed: serde_json::Value = serde_json::from_str(&content).unwrap();
assert_eq!(parsed["server"]["heartbeat_ms"], 1618);
assert_eq!(parsed["server"]["idle_timeout_ms"], 21034);
assert_eq!(parsed["limits"]["gate_closing_ticks"], 7);
assert_eq!(parsed["limits"]["max_sessions"], 1024);
assert_eq!(parsed["identity"]["min_interactions"], 21);
let _ = std::fs::remove_dir_all(&dir);
}
#[test]
fn blake3_digest_deterministic() {
let dir1 = std::env::temp_dir().join("hello_universe_det1");
let dir2 = std::env::temp_dir().join("hello_universe_det2");
let r1 = generate(&dir1, "det-test").unwrap();
let r2 = generate(&dir2, "det-test").unwrap();
assert_eq!(r1.landing_digest_hex, r2.landing_digest_hex);
let _ = std::fs::remove_dir_all(&dir1);
let _ = std::fs::remove_dir_all(&dir2);
}
#[test]
fn readme_references_project_name() {
let dir = std::env::temp_dir().join("hello_universe_readme");
generate(&dir, "readme-test").unwrap();
let content = std::fs::read_to_string(dir.join("README.md")).unwrap();
assert!(content.contains("readme-test"));
assert!(content.contains("dream up --hello-universe"));
let _ = std::fs::remove_dir_all(&dir);
}
#[test]
fn default_dimensions() {
assert_eq!(DEFAULT_WIDTH, 1920);
assert_eq!(DEFAULT_HEIGHT, 1080);
}
#[test]
fn display_does_not_panic() {
let dir = std::env::temp_dir().join("hello_universe_display");
let result = generate(&dir, "display-test").unwrap();
result.display(); let _ = std::fs::remove_dir_all(&dir);
}
}