adding details
This commit is contained in:
166
DATABASE_SETUP.md
Normal file
166
DATABASE_SETUP.md
Normal file
@@ -0,0 +1,166 @@
|
||||
# RisingCompute — PostgreSQL Setup
|
||||
|
||||
This is the database side of the RisingCompute site. The Django backend connects to a single PostgreSQL database called `risingcompute`. Follow these steps on the **server** (or your dev laptop) before running `python manage.py migrate`.
|
||||
|
||||
---
|
||||
|
||||
## 1. Install PostgreSQL
|
||||
|
||||
### Ubuntu / Debian server
|
||||
```bash
|
||||
sudo apt update
|
||||
sudo apt install -y postgresql postgresql-contrib
|
||||
sudo systemctl enable --now postgresql
|
||||
```
|
||||
|
||||
### macOS (development)
|
||||
```bash
|
||||
brew install postgresql@16
|
||||
brew services start postgresql@16
|
||||
```
|
||||
|
||||
### Verify
|
||||
```bash
|
||||
psql --version
|
||||
# expect: psql (PostgreSQL) 14.x or newer
|
||||
```
|
||||
|
||||
Use **PostgreSQL 14+** — Django 5 supports 13+, but 16 is the recommended LTS as of this build.
|
||||
|
||||
---
|
||||
|
||||
## 2. Create the database and user
|
||||
|
||||
Switch to the `postgres` superuser and open a `psql` shell:
|
||||
|
||||
```bash
|
||||
sudo -u postgres psql
|
||||
```
|
||||
|
||||
Then, inside `psql`, paste these four statements (edit the password to something strong):
|
||||
|
||||
```sql
|
||||
CREATE USER risingcompute WITH PASSWORD 'change-this-to-a-strong-password';
|
||||
CREATE DATABASE risingcompute OWNER risingcompute ENCODING 'UTF8';
|
||||
GRANT ALL PRIVILEGES ON DATABASE risingcompute TO risingcompute;
|
||||
ALTER USER risingcompute CREATEDB; -- needed for running tests
|
||||
\q
|
||||
```
|
||||
|
||||
The `CREATEDB` privilege is only needed if you want to run Django's test suite (which creates a throwaway `test_risingcompute` DB).
|
||||
|
||||
---
|
||||
|
||||
## 3. Allow local TCP connections (server only)
|
||||
|
||||
By default, PostgreSQL on Linux only accepts Unix-socket connections from local users. Django connects over TCP, so enable `md5` (password) auth on `127.0.0.1`.
|
||||
|
||||
Edit `/etc/postgresql/16/main/pg_hba.conf` (adjust the version number) and make sure these two lines exist near the top:
|
||||
|
||||
```
|
||||
# TYPE DATABASE USER ADDRESS METHOD
|
||||
local all all peer
|
||||
host risingcompute risingcompute 127.0.0.1/32 md5
|
||||
host risingcompute risingcompute ::1/128 md5
|
||||
```
|
||||
|
||||
Reload:
|
||||
|
||||
```bash
|
||||
sudo systemctl reload postgresql
|
||||
```
|
||||
|
||||
On macOS via Homebrew, this is already set up — no edit needed.
|
||||
|
||||
---
|
||||
|
||||
## 4. Test the connection
|
||||
|
||||
```bash
|
||||
psql -h 127.0.0.1 -U risingcompute -d risingcompute -W
|
||||
# enter the password you set above
|
||||
# you should land at: risingcompute=>
|
||||
\q
|
||||
```
|
||||
|
||||
If you can connect, the database side is done.
|
||||
|
||||
---
|
||||
|
||||
## 5. Wire it into Django
|
||||
|
||||
In `backend/.env` (copy from `backend/.env.example`), set:
|
||||
|
||||
```
|
||||
DATABASE_URL=postgres://risingcompute:your-password-here@127.0.0.1:5432/risingcompute
|
||||
DJANGO_SECRET_KEY=generate-a-50-char-random-string
|
||||
DJANGO_DEBUG=False
|
||||
DJANGO_ALLOWED_HOSTS=risingcompute.in,www.risingcompute.in,localhost,127.0.0.1
|
||||
CORS_ALLOWED_ORIGINS=https://risingcompute.in,https://www.risingcompute.in,http://localhost:5173
|
||||
```
|
||||
|
||||
Generate a Django secret key:
|
||||
|
||||
```bash
|
||||
python -c "from secrets import token_urlsafe; print(token_urlsafe(50))"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. Run migrations and create the admin user
|
||||
|
||||
From `backend/`:
|
||||
|
||||
```bash
|
||||
python -m venv .venv
|
||||
source .venv/bin/activate # Windows: .venv\Scripts\activate
|
||||
pip install -r requirements.txt
|
||||
|
||||
python manage.py migrate
|
||||
python manage.py createsuperuser
|
||||
python manage.py runserver 0.0.0.0:8000
|
||||
```
|
||||
|
||||
Visit `http://127.0.0.1:8000/admin/` and sign in. You should see `Contact submissions`, `Newsletter signups`, `Job applications`, `Blog posts`, and `Products` (seeded by the data migration).
|
||||
|
||||
---
|
||||
|
||||
## 7. Production checklist
|
||||
|
||||
When you deploy to a real server:
|
||||
|
||||
- [ ] Set `DJANGO_DEBUG=False`
|
||||
- [ ] Generate a fresh `DJANGO_SECRET_KEY` (do not reuse the dev key)
|
||||
- [ ] Use a separate Postgres user per environment (staging / prod)
|
||||
- [ ] Put Django behind Gunicorn + Nginx (or any WSGI host)
|
||||
- [ ] Enable TLS on the database connection (`?sslmode=require` in `DATABASE_URL`) if the DB is on a different host
|
||||
- [ ] Schedule daily `pg_dump` backups to object storage
|
||||
- [ ] Restrict the Postgres port (5432) at the firewall — only the app server should reach it
|
||||
- [ ] Rotate the database password and the Django secret key on a schedule
|
||||
|
||||
---
|
||||
|
||||
## 8. Backup & restore (one-liners)
|
||||
|
||||
**Backup:**
|
||||
```bash
|
||||
pg_dump -h 127.0.0.1 -U risingcompute -Fc risingcompute > risingcompute-$(date +%Y%m%d).dump
|
||||
```
|
||||
|
||||
**Restore (into an empty database):**
|
||||
```bash
|
||||
pg_restore -h 127.0.0.1 -U risingcompute -d risingcompute --clean --if-exists risingcompute-YYYYMMDD.dump
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. Common errors
|
||||
|
||||
| Error | Fix |
|
||||
|---|---|
|
||||
| `FATAL: password authentication failed` | Re-check the password in `DATABASE_URL`; make sure `pg_hba.conf` uses `md5` for the host line. |
|
||||
| `could not connect to server: Connection refused` | PostgreSQL isn't running. `sudo systemctl status postgresql`. |
|
||||
| `permission denied for schema public` (PG 15+) | Run as superuser: `GRANT ALL ON SCHEMA public TO risingcompute;` |
|
||||
| `relation "..." does not exist` | You haven't run `python manage.py migrate` yet. |
|
||||
|
||||
That's the whole database side. The Django app picks up `DATABASE_URL` automatically — no other config needed.
|
||||
164
README.md
164
README.md
@@ -1 +1,163 @@
|
||||
This is first file of rising web
|
||||
# RisingCompute Website
|
||||
|
||||
The marketing site for **RisingCompute** — IP cores for AI, space, and robotics.
|
||||
|
||||
- **Backend:** Django 5 + Django REST Framework + PostgreSQL
|
||||
- **Frontend:** Vue 3 + Vite + Vue Router
|
||||
- **Deployment:** any WSGI host (gunicorn + nginx) + a static-file host for the SPA
|
||||
|
||||
---
|
||||
|
||||
## Layout
|
||||
|
||||
```
|
||||
rising-web/
|
||||
├── backend/ # Django project
|
||||
│ ├── risingcompute/ # Project settings, urls, wsgi, asgi
|
||||
│ ├── api/ # The "api" app — models, views, serializers, admin
|
||||
│ │ └── migrations/ # Schema + seed data
|
||||
│ ├── manage.py
|
||||
│ ├── requirements.txt
|
||||
│ └── .env.example
|
||||
├── frontend/ # Vue 3 SPA (Vite)
|
||||
│ ├── src/
|
||||
│ │ ├── components/
|
||||
│ │ ├── views/
|
||||
│ │ ├── router/
|
||||
│ │ ├── api/
|
||||
│ │ └── assets/styles/
|
||||
│ ├── package.json
|
||||
│ ├── vite.config.js
|
||||
│ └── .env.example
|
||||
├── DATABASE_SETUP.md # PostgreSQL install + provisioning
|
||||
├── design-document.md # Empty template (origin)
|
||||
├── filled_design_document.md # Founder-filled version
|
||||
└── final_design_document.md # Build-ready spec (source of truth)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Quick start (development)
|
||||
|
||||
You'll need: Python 3.11+, Node 20+, PostgreSQL 14+.
|
||||
|
||||
### 1. Provision the database
|
||||
|
||||
Follow [DATABASE_SETUP.md](./DATABASE_SETUP.md). At the end of it you should have:
|
||||
|
||||
- a running PostgreSQL with a database called `risingcompute`
|
||||
- a user called `risingcompute` with a strong password
|
||||
- a `DATABASE_URL` you can paste into `backend/.env`
|
||||
|
||||
### 2. Run the backend
|
||||
|
||||
```bash
|
||||
cd backend
|
||||
cp .env.example .env # then edit DATABASE_URL + SECRET_KEY
|
||||
python -m venv .venv
|
||||
source .venv/bin/activate # Windows: .venv\Scripts\activate
|
||||
pip install -r requirements.txt
|
||||
python manage.py migrate # also seeds products, founders, blog posts
|
||||
python manage.py createsuperuser
|
||||
python manage.py runserver 0.0.0.0:8000
|
||||
```
|
||||
|
||||
Backend lives at `http://127.0.0.1:8000`. Useful URLs:
|
||||
|
||||
- `http://127.0.0.1:8000/admin/` — Django admin (manage products, blog, openings, submissions)
|
||||
- `http://127.0.0.1:8000/api/health/` — uptime check
|
||||
- `http://127.0.0.1:8000/api/products/` — JSON list of IP cores
|
||||
- `http://127.0.0.1:8000/api/founders/` — founder profiles
|
||||
- `http://127.0.0.1:8000/api/posts/` — blog post list
|
||||
|
||||
### 3. Run the frontend
|
||||
|
||||
```bash
|
||||
cd frontend
|
||||
cp .env.example .env # optional in dev (proxy handles it)
|
||||
npm install
|
||||
npm run dev
|
||||
```
|
||||
|
||||
Frontend lives at `http://127.0.0.1:5173`. Vite proxies `/api/*` to Django on `:8000`, so the SPA and backend behave as same-origin during dev.
|
||||
|
||||
### 4. Sign in to admin and check
|
||||
|
||||
Visit `http://127.0.0.1:8000/admin/`, sign in with the superuser you created, and verify that **Products**, **Founders**, and **Blog posts** are all populated by the seed migration.
|
||||
|
||||
Open `http://127.0.0.1:5173/` — you should see the RisingCompute homepage with three product cards and three blog teasers loaded from the API.
|
||||
|
||||
---
|
||||
|
||||
## API contract
|
||||
|
||||
| Method | Endpoint | Purpose |
|
||||
|---|---|---|
|
||||
| GET | `/api/health/` | Service uptime |
|
||||
| GET | `/api/products/` | List published products |
|
||||
| GET | `/api/products/<slug>/` | Single product |
|
||||
| GET | `/api/founders/` | Founder profiles for the About page |
|
||||
| GET | `/api/posts/` | List published blog posts |
|
||||
| GET | `/api/posts/<slug>/` | Single post |
|
||||
| GET | `/api/jobs/` | Open roles |
|
||||
| POST | `/api/contact/` | Submit the contact / evaluation form |
|
||||
| POST | `/api/newsletter/` | Newsletter signup |
|
||||
| POST | `/api/apply/` | Job application (multipart, supports CV upload) |
|
||||
|
||||
Submission endpoints are rate-limited to 30/hour per anonymous IP.
|
||||
|
||||
---
|
||||
|
||||
## Deployment
|
||||
|
||||
**Backend (Django):**
|
||||
|
||||
1. Provision a VM (Ubuntu 22+) and follow [DATABASE_SETUP.md](./DATABASE_SETUP.md).
|
||||
2. Set `DJANGO_DEBUG=False`, a real `DJANGO_SECRET_KEY`, real `DJANGO_ALLOWED_HOSTS`, and a real `DATABASE_URL` in `backend/.env`.
|
||||
3. `pip install -r requirements.txt`
|
||||
4. `python manage.py migrate && python manage.py collectstatic --noinput`
|
||||
5. Run with gunicorn behind nginx:
|
||||
```bash
|
||||
gunicorn risingcompute.wsgi:application --bind 0.0.0.0:8000 --workers 3
|
||||
```
|
||||
6. Point nginx at gunicorn for `/api/` and `/admin/`, and serve `/static/` from `backend/staticfiles/`.
|
||||
|
||||
**Frontend (Vue SPA):**
|
||||
|
||||
1. Set `VITE_API_BASE_URL=https://risingcompute.in` (or your API host).
|
||||
2. `npm run build` → produces `frontend/dist/`.
|
||||
3. Serve the `dist/` folder from any static host (nginx, Vercel, Cloudflare Pages, Netlify, S3+CloudFront). Make sure unknown paths fall back to `index.html` (SPA history mode).
|
||||
|
||||
---
|
||||
|
||||
## Editing content
|
||||
|
||||
All marketing content is editable from the Django admin:
|
||||
|
||||
- **Products** — name, tagline, summary, description, benefits, features, spec table (JSON).
|
||||
- **Founders** — bios, photo URLs, LinkedIn.
|
||||
- **Blog posts** — title, excerpt, markdown body, category, author.
|
||||
- **Job openings** — open / closed, description, location.
|
||||
- **Submissions** — Contact submissions, Newsletter signups, Job applications all show up here for triage.
|
||||
|
||||
The seed migration (`api/migrations/0002_seed_initial_data.py`) populates the initial copy. Re-running migrations does not overwrite edits you've made in the admin (it uses `update_or_create`, so it will re-sync defaults — edit copy in the admin to make changes stick).
|
||||
|
||||
---
|
||||
|
||||
## Brand reference
|
||||
|
||||
Aligned with the company core values — **Fast · Reliable · Robust**.
|
||||
|
||||
- Primary: `#0B1437` (Deep Space Indigo)
|
||||
- Surface: `#1A2347` (Slate Navy)
|
||||
- Accent: `#00E5FF` (Accelerate Cyan)
|
||||
- Text: `#F4F6FB` (Mist)
|
||||
- Type: Inter + JetBrains Mono
|
||||
- Default theme: dark
|
||||
- Motion: subtle (fade-ins, hover lifts, one animated hero datapath). Respects `prefers-reduced-motion`.
|
||||
|
||||
---
|
||||
|
||||
## License
|
||||
|
||||
Proprietary. © RisingCompute Pvt Ltd.
|
||||
|
||||
7
backend/.env.example
Normal file
7
backend/.env.example
Normal file
@@ -0,0 +1,7 @@
|
||||
# Copy this file to `.env` and fill in real values.
|
||||
DJANGO_SECRET_KEY=replace-me-with-a-50-char-random-string
|
||||
DJANGO_DEBUG=True
|
||||
DJANGO_ALLOWED_HOSTS=localhost,127.0.0.1
|
||||
DATABASE_URL=postgres://risingcompute:change-this-password@127.0.0.1:5432/risingcompute
|
||||
CORS_ALLOWED_ORIGINS=http://localhost:5173,http://127.0.0.1:5173
|
||||
NOTIFY_EMAIL_TO=contact@risingcompute.in
|
||||
0
backend/api/__init__.py
Normal file
0
backend/api/__init__.py
Normal file
BIN
backend/api/__pycache__/__init__.cpython-310.pyc
Normal file
BIN
backend/api/__pycache__/__init__.cpython-310.pyc
Normal file
Binary file not shown.
BIN
backend/api/__pycache__/admin.cpython-310.pyc
Normal file
BIN
backend/api/__pycache__/admin.cpython-310.pyc
Normal file
Binary file not shown.
BIN
backend/api/__pycache__/apps.cpython-310.pyc
Normal file
BIN
backend/api/__pycache__/apps.cpython-310.pyc
Normal file
Binary file not shown.
BIN
backend/api/__pycache__/models.cpython-310.pyc
Normal file
BIN
backend/api/__pycache__/models.cpython-310.pyc
Normal file
Binary file not shown.
BIN
backend/api/__pycache__/serializers.cpython-310.pyc
Normal file
BIN
backend/api/__pycache__/serializers.cpython-310.pyc
Normal file
Binary file not shown.
BIN
backend/api/__pycache__/urls.cpython-310.pyc
Normal file
BIN
backend/api/__pycache__/urls.cpython-310.pyc
Normal file
Binary file not shown.
BIN
backend/api/__pycache__/views.cpython-310.pyc
Normal file
BIN
backend/api/__pycache__/views.cpython-310.pyc
Normal file
Binary file not shown.
76
backend/api/admin.py
Normal file
76
backend/api/admin.py
Normal file
@@ -0,0 +1,76 @@
|
||||
from django.contrib import admin
|
||||
|
||||
from .models import (
|
||||
BlogPost,
|
||||
ContactSubmission,
|
||||
Founder,
|
||||
JobApplication,
|
||||
JobOpening,
|
||||
NewsletterSignup,
|
||||
Product,
|
||||
)
|
||||
|
||||
|
||||
@admin.register(Product)
|
||||
class ProductAdmin(admin.ModelAdmin):
|
||||
list_display = ("name", "category", "is_published", "sort_order", "updated_at")
|
||||
list_filter = ("category", "is_published")
|
||||
search_fields = ("name", "tagline", "slug")
|
||||
prepopulated_fields = {"slug": ("name",)}
|
||||
|
||||
|
||||
@admin.register(Founder)
|
||||
class FounderAdmin(admin.ModelAdmin):
|
||||
list_display = ("name", "role", "is_published", "sort_order")
|
||||
list_filter = ("is_published",)
|
||||
search_fields = ("name", "role")
|
||||
|
||||
|
||||
@admin.register(BlogPost)
|
||||
class BlogPostAdmin(admin.ModelAdmin):
|
||||
list_display = ("title", "category", "author_name", "is_published", "published_at")
|
||||
list_filter = ("category", "is_published")
|
||||
search_fields = ("title", "excerpt", "body")
|
||||
prepopulated_fields = {"slug": ("title",)}
|
||||
date_hierarchy = "published_at"
|
||||
|
||||
|
||||
@admin.register(JobOpening)
|
||||
class JobOpeningAdmin(admin.ModelAdmin):
|
||||
list_display = ("title", "location", "employment_type", "is_open", "posted_at")
|
||||
list_filter = ("location", "is_open")
|
||||
search_fields = ("title", "description")
|
||||
prepopulated_fields = {"slug": ("title",)}
|
||||
|
||||
|
||||
@admin.register(ContactSubmission)
|
||||
class ContactSubmissionAdmin(admin.ModelAdmin):
|
||||
list_display = ("name", "email", "interest", "company", "created_at")
|
||||
list_filter = ("interest", "created_at")
|
||||
search_fields = ("name", "email", "company", "message")
|
||||
readonly_fields = (
|
||||
"name",
|
||||
"email",
|
||||
"company",
|
||||
"role",
|
||||
"country",
|
||||
"interest",
|
||||
"message",
|
||||
"referrer",
|
||||
"user_agent",
|
||||
"ip_address",
|
||||
"created_at",
|
||||
)
|
||||
|
||||
|
||||
@admin.register(NewsletterSignup)
|
||||
class NewsletterSignupAdmin(admin.ModelAdmin):
|
||||
list_display = ("email", "source", "confirmed", "created_at")
|
||||
list_filter = ("source", "confirmed")
|
||||
search_fields = ("email",)
|
||||
|
||||
|
||||
@admin.register(JobApplication)
|
||||
class JobApplicationAdmin(admin.ModelAdmin):
|
||||
list_display = ("name", "email", "role_applied_for", "created_at")
|
||||
search_fields = ("name", "email", "role_applied_for")
|
||||
7
backend/api/apps.py
Normal file
7
backend/api/apps.py
Normal file
@@ -0,0 +1,7 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class ApiConfig(AppConfig):
|
||||
default_auto_field = "django.db.models.BigAutoField"
|
||||
name = "api"
|
||||
verbose_name = "RisingCompute API"
|
||||
126
backend/api/migrations/0001_initial.py
Normal file
126
backend/api/migrations/0001_initial.py
Normal file
@@ -0,0 +1,126 @@
|
||||
# Generated by Django 5.0.6
|
||||
|
||||
import django.utils.timezone
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = []
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='BlogPost',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('slug', models.SlugField(max_length=200, unique=True)),
|
||||
('title', models.CharField(max_length=200)),
|
||||
('excerpt', models.CharField(max_length=300)),
|
||||
('body', models.TextField(help_text='Markdown.')),
|
||||
('category', models.CharField(choices=[('ai', 'AI'), ('space', 'Space'), ('robotics', 'Robotics'), ('engineering', 'Engineering'), ('company', 'Company')], default='company', max_length=20)),
|
||||
('author_name', models.CharField(max_length=120)),
|
||||
('read_time_minutes', models.PositiveIntegerField(default=5)),
|
||||
('cover_image_url', models.URLField(blank=True)),
|
||||
('is_published', models.BooleanField(default=True)),
|
||||
('published_at', models.DateTimeField(default=django.utils.timezone.now)),
|
||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||
('updated_at', models.DateTimeField(auto_now=True)),
|
||||
],
|
||||
options={'ordering': ['-published_at']},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='ContactSubmission',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=120)),
|
||||
('email', models.EmailField(max_length=254)),
|
||||
('company', models.CharField(blank=True, max_length=160)),
|
||||
('role', models.CharField(blank=True, max_length=120)),
|
||||
('country', models.CharField(blank=True, max_length=80)),
|
||||
('interest', models.CharField(choices=[('ai-ip', 'AI Inference IP'), ('security-ip', 'Cybersecurity IP'), ('comms-ip', 'Communication IP'), ('custom-asic', 'Custom ASIC'), ('careers', 'Careers'), ('press', 'Press'), ('other', 'Other')], default='other', max_length=20)),
|
||||
('message', models.TextField()),
|
||||
('referrer', models.CharField(blank=True, max_length=200)),
|
||||
('user_agent', models.CharField(blank=True, max_length=400)),
|
||||
('ip_address', models.GenericIPAddressField(blank=True, null=True)),
|
||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||
],
|
||||
options={'verbose_name': 'Contact submission', 'ordering': ['-created_at']},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Founder',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=120)),
|
||||
('role', models.CharField(max_length=160)),
|
||||
('domain', models.CharField(help_text='Short description of the technical domain they own.', max_length=240)),
|
||||
('bio', models.TextField(help_text='~80-word bio. Markdown allowed.')),
|
||||
('photo_url', models.URLField(blank=True)),
|
||||
('linkedin_url', models.URLField(blank=True)),
|
||||
('sort_order', models.PositiveIntegerField(default=0)),
|
||||
('is_published', models.BooleanField(default=True)),
|
||||
],
|
||||
options={'ordering': ['sort_order', 'name']},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='JobApplication',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=120)),
|
||||
('email', models.EmailField(max_length=254)),
|
||||
('role_applied_for', models.CharField(max_length=160)),
|
||||
('portfolio_url', models.URLField(blank=True)),
|
||||
('message', models.TextField(blank=True)),
|
||||
('cv', models.FileField(blank=True, null=True, upload_to='applications/%Y/%m/')),
|
||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||
],
|
||||
options={'ordering': ['-created_at']},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='JobOpening',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('slug', models.SlugField(max_length=120, unique=True)),
|
||||
('title', models.CharField(max_length=160)),
|
||||
('location', models.CharField(choices=[('surat', 'Surat, India'), ('iist', 'STIIC / IIST, Thiruvananthapuram'), ('remote', 'Remote (India)'), ('hybrid', 'Hybrid')], default='surat', max_length=20)),
|
||||
('employment_type', models.CharField(default='Full-time', max_length=40)),
|
||||
('description', models.TextField(help_text='Markdown.')),
|
||||
('is_open', models.BooleanField(default=True)),
|
||||
('posted_at', models.DateField(default=django.utils.timezone.now)),
|
||||
],
|
||||
options={'ordering': ['-posted_at']},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='NewsletterSignup',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('email', models.EmailField(max_length=254, unique=True)),
|
||||
('source', models.CharField(blank=True, help_text='e.g. footer, blog, contact', max_length=120)),
|
||||
('confirmed', models.BooleanField(default=False)),
|
||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||
],
|
||||
options={'ordering': ['-created_at']},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Product',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('slug', models.SlugField(max_length=80, unique=True)),
|
||||
('name', models.CharField(max_length=120)),
|
||||
('category', models.CharField(choices=[('ai', 'AI Inference'), ('security', 'Cybersecurity'), ('comms', 'Communication Protocol'), ('asic', 'Custom ASIC Services'), ('other', 'Other')], max_length=20)),
|
||||
('tagline', models.CharField(max_length=200)),
|
||||
('summary', models.TextField(help_text='2–3 sentence overview shown on the products grid.')),
|
||||
('description', models.TextField(help_text='Long-form description shown on the product detail page (markdown).')),
|
||||
('benefits', models.JSONField(blank=True, default=list, help_text='List of benefit strings. Example: ["High throughput per watt", "INT8/INT4"].')),
|
||||
('features', models.JSONField(blank=True, default=list)),
|
||||
('spec_table', models.JSONField(blank=True, default=list, help_text='List of {"label": "...", "value": "..."} pairs for the spec table.')),
|
||||
('primary_cta_label', models.CharField(default='Request evaluation', max_length=60)),
|
||||
('is_published', models.BooleanField(default=True)),
|
||||
('sort_order', models.PositiveIntegerField(default=0)),
|
||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||
('updated_at', models.DateTimeField(auto_now=True)),
|
||||
],
|
||||
options={'ordering': ['sort_order', 'name']},
|
||||
),
|
||||
]
|
||||
268
backend/api/migrations/0002_seed_initial_data.py
Normal file
268
backend/api/migrations/0002_seed_initial_data.py
Normal file
@@ -0,0 +1,268 @@
|
||||
"""Seed the database with the launch content (products, founders, blog)."""
|
||||
from django.db import migrations
|
||||
from django.utils import timezone
|
||||
|
||||
|
||||
PRODUCTS = [
|
||||
{
|
||||
"slug": "ai-inference-ip",
|
||||
"name": "AI Inference IP Core",
|
||||
"category": "ai",
|
||||
"tagline": "Parallel inference at the edge — deterministic, quantised, portable.",
|
||||
"summary": (
|
||||
"A parallel-compute IP core for running quantised neural networks on FPGA "
|
||||
"or ASIC. Built for vision, sensor fusion, and on-orbit inference."
|
||||
),
|
||||
"description": (
|
||||
"Our AI Inference IP Core is designed for workloads where GPUs are too "
|
||||
"power-hungry and general-purpose NPUs are too opaque. It runs INT8 / INT4 "
|
||||
"quantised networks with deterministic latency, ports cleanly from FPGA "
|
||||
"prototype to ASIC tape-out, and is verifiable end-to-end."
|
||||
),
|
||||
"benefits": [
|
||||
"Higher throughput-per-watt than CPU / GPU at the edge",
|
||||
"Deterministic latency for real-time control loops",
|
||||
"INT8 / INT4 quantisation-aware datapath",
|
||||
"Synthesises on standard FPGA tooling",
|
||||
"Same RTL portable from FPGA to ASIC",
|
||||
],
|
||||
"features": [
|
||||
"Parameterised RTL",
|
||||
"Reference compiler for an ONNX subset",
|
||||
"FPGA reference design",
|
||||
"Integration guide & testbench",
|
||||
],
|
||||
"spec_table": [
|
||||
{"label": "Interface", "value": "AXI4 / AXI-Stream"},
|
||||
{"label": "Precision", "value": "INT8 / INT4"},
|
||||
{"label": "Targets", "value": "Xilinx UltraScale+, Intel Agilex, 28nm ASIC"},
|
||||
{"label": "Verification", "value": "UVM testbench included"},
|
||||
],
|
||||
"primary_cta_label": "Request evaluation",
|
||||
"sort_order": 1,
|
||||
},
|
||||
{
|
||||
"slug": "cybersecurity-ip",
|
||||
"name": "Cybersecurity IP Core",
|
||||
"category": "security",
|
||||
"tagline": "Hardware-accelerated cryptography — side-channel hardened.",
|
||||
"summary": (
|
||||
"A drop-in hardware accelerator for symmetric and asymmetric cryptography "
|
||||
"and secure boot — built for defense electronics and secure-element SoCs."
|
||||
),
|
||||
"description": (
|
||||
"Hardware acceleration for AES, SHA, ECC and RSA primitives, plus a secure "
|
||||
"boot block. Designed constant-time and side-channel hardened from the "
|
||||
"first line of RTL — security is not a wrapper, it's the architecture."
|
||||
),
|
||||
"benefits": [
|
||||
"Constant-time implementation",
|
||||
"Side-channel hardened",
|
||||
"FIPS-aligned algorithm set",
|
||||
"Low gate count for embedded targets",
|
||||
],
|
||||
"features": [
|
||||
"AES-128 / 256, SHA-2 / 3",
|
||||
"ECC (P-256, P-384), RSA-2048 / 4096",
|
||||
"True random number generator interface",
|
||||
"AXI / AHB wrappers",
|
||||
"Security white paper",
|
||||
],
|
||||
"spec_table": [
|
||||
{"label": "Interface", "value": "AXI4-Lite / AHB-Lite"},
|
||||
{"label": "Algorithms", "value": "AES, SHA-2/3, ECC, RSA"},
|
||||
{"label": "Targets", "value": "FPGA + 28/40nm ASIC"},
|
||||
{"label": "Compliance", "value": "FIPS-aligned"},
|
||||
],
|
||||
"primary_cta_label": "Request evaluation",
|
||||
"sort_order": 2,
|
||||
},
|
||||
{
|
||||
"slug": "communication-ip",
|
||||
"name": "Communication Protocol IP",
|
||||
"category": "comms",
|
||||
"tagline": "Space- and avionics-grade communication blocks. Flight-proven.",
|
||||
"summary": (
|
||||
"SpaceWire, CAN, UART/SPI/I2C and custom satellite payload buses — "
|
||||
"low gate-count, well-documented, and flight-proven on operational missions."
|
||||
),
|
||||
"description": (
|
||||
"Our communication IP catalogue is the most battle-tested part of our "
|
||||
"stack — variants of these cores have flown on operational satellite "
|
||||
"missions. We licence the same blocks to ground systems, payload "
|
||||
"integrators, and avionics OEMs."
|
||||
),
|
||||
"benefits": [
|
||||
"Space-qualified design practice",
|
||||
"Low gate-count for power-constrained targets",
|
||||
"Flight-heritage documentation",
|
||||
"Comprehensive verification IP",
|
||||
],
|
||||
"features": [
|
||||
"SpaceWire / SpaceFibre",
|
||||
"CAN-FD",
|
||||
"UART / SPI / I2C masters & slaves",
|
||||
"Custom satellite payload buses",
|
||||
"Reference designs + integration guide",
|
||||
],
|
||||
"spec_table": [
|
||||
{"label": "Protocols", "value": "SpaceWire, CAN-FD, UART, SPI, I2C"},
|
||||
{"label": "Heritage", "value": "Flown on operational satellite missions"},
|
||||
{"label": "Verification", "value": "Protocol-compliant testbenches"},
|
||||
],
|
||||
"primary_cta_label": "Request evaluation",
|
||||
"sort_order": 3,
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
FOUNDERS = [
|
||||
{
|
||||
"name": "Ali Murabbi",
|
||||
"role": "Co-founder · VLSI & Robotics Engineer",
|
||||
"domain": "RTL / FPGA design · robotics control hardware · motion and sensor-fusion blocks",
|
||||
"bio": (
|
||||
"Hardware designer specialising in RTL and FPGA for robotics and motion "
|
||||
"systems. At SSPACE, IIST, contributed to onboard compute blocks for "
|
||||
"satellite payloads and now leads RisingCompute's communication-protocol "
|
||||
"and robotics IP work."
|
||||
),
|
||||
"sort_order": 1,
|
||||
},
|
||||
{
|
||||
"name": "Bhavy Savani",
|
||||
"role": "Co-founder · VLSI & AI Engineer",
|
||||
"domain": "RTL / FPGA design · quantised neural-network accelerators · verification",
|
||||
"bio": (
|
||||
"VLSI engineer focused on AI accelerator architectures and verification. "
|
||||
"At SSPACE, IIST, designed and verified compute IP that has flown in "
|
||||
"space; at RisingCompute, leads the AI Inference IP Core and the "
|
||||
"Cybersecurity IP Core."
|
||||
),
|
||||
"sort_order": 2,
|
||||
},
|
||||
{
|
||||
"name": "Abhishek Verma",
|
||||
"role": "Co-founder · System Engineer & Project Manager",
|
||||
"domain": "System architecture · integration · project delivery · GTM",
|
||||
"bio": (
|
||||
"Systems engineer and programme lead. Brings the IP, the engineering "
|
||||
"team, and the customer programme together — sets architecture, owns "
|
||||
"project delivery, and runs partner and customer conversations."
|
||||
),
|
||||
"sort_order": 3,
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
BLOG_POSTS = [
|
||||
{
|
||||
"slug": "why-we-started-risingcompute",
|
||||
"title": "Why we started RisingCompute",
|
||||
"excerpt": (
|
||||
"Two years inside a satellite-software lab taught us something simple: "
|
||||
"the difference between what a research team can do with AI and what most "
|
||||
"engineers can do comes down to compute. We started RisingCompute to close "
|
||||
"that gap."
|
||||
),
|
||||
"category": "company",
|
||||
"author_name": "Abhishek Verma",
|
||||
"read_time_minutes": 4,
|
||||
"body": (
|
||||
"## A note from the founders\n\n"
|
||||
"RisingCompute was born inside the SSPACE lab at IIST. We spent two "
|
||||
"years building computation systems for satellites — IP that has since "
|
||||
"flown in space. What we kept noticing was the gap between what a "
|
||||
"research team can do with the right hardware and what a typical "
|
||||
"product team can do with whatever GPU they could afford.\n\n"
|
||||
"Our bet is that closing that gap is a hardware problem, not a "
|
||||
"software one. Parallel architectures, well-designed IP cores, and a "
|
||||
"vendor that ships datasheets you can actually read."
|
||||
),
|
||||
},
|
||||
{
|
||||
"slug": "what-flight-heritage-means-for-ip",
|
||||
"title": "What flight heritage actually means for IP cores",
|
||||
"excerpt": (
|
||||
"\"Flight-heritage\" is one of the most over-claimed phrases in the IP "
|
||||
"industry. Here's what it means to us, what it doesn't, and what to "
|
||||
"ask the next vendor that uses the term."
|
||||
),
|
||||
"category": "space",
|
||||
"author_name": "Ali Murabbi",
|
||||
"read_time_minutes": 6,
|
||||
"body": (
|
||||
"## What counts, and what doesn't\n\n"
|
||||
"Flight heritage is not just \"this RTL was synthesised onto a flight "
|
||||
"FPGA once.\" Real heritage is end-to-end: a documented chain from RTL "
|
||||
"to verification artifacts to a specific board, on a specific mission, "
|
||||
"with a specific telemetry track."
|
||||
),
|
||||
},
|
||||
{
|
||||
"slug": "int8-inference-without-accuracy-loss",
|
||||
"title": "Designing AI inference cores for INT8 without accuracy loss",
|
||||
"excerpt": (
|
||||
"Quantisation is a free lunch — until it isn't. A practical walk "
|
||||
"through the datapath choices that decide whether INT8 inference is "
|
||||
"production-ready or just a benchmark trick."
|
||||
),
|
||||
"category": "ai",
|
||||
"author_name": "Bhavy Savani",
|
||||
"read_time_minutes": 8,
|
||||
"body": (
|
||||
"## The two failure modes\n\n"
|
||||
"Most INT8 implementations fail in one of two ways: accuracy collapse "
|
||||
"from poor calibration, or throughput collapse from naive datapath "
|
||||
"layout. We walk through how we designed around both."
|
||||
),
|
||||
},
|
||||
{
|
||||
"slug": "indian-sovereign-ip-stack",
|
||||
"title": "An Indian sovereign IP stack — and why it matters now",
|
||||
"excerpt": (
|
||||
"\"Make in India\" content rules are reshaping defense and space "
|
||||
"procurement. A founder note on what an Indian-origin IP stack should "
|
||||
"look like — and what it shouldn't."
|
||||
),
|
||||
"category": "company",
|
||||
"author_name": "Abhishek Verma",
|
||||
"read_time_minutes": 5,
|
||||
"body": (
|
||||
"## Sovereign doesn't mean isolated\n\n"
|
||||
"Sovereign IP should mean Indian-origin design, Indian-origin "
|
||||
"verification, and an Indian-origin support chain. It does not mean "
|
||||
"rejecting global tooling or global customers."
|
||||
),
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
def seed(apps, schema_editor):
|
||||
Product = apps.get_model("api", "Product")
|
||||
Founder = apps.get_model("api", "Founder")
|
||||
BlogPost = apps.get_model("api", "BlogPost")
|
||||
|
||||
for row in PRODUCTS:
|
||||
Product.objects.update_or_create(slug=row["slug"], defaults=row)
|
||||
for row in FOUNDERS:
|
||||
Founder.objects.update_or_create(name=row["name"], defaults=row)
|
||||
for row in BLOG_POSTS:
|
||||
BlogPost.objects.update_or_create(
|
||||
slug=row["slug"],
|
||||
defaults={**row, "published_at": timezone.now()},
|
||||
)
|
||||
|
||||
|
||||
def unseed(apps, schema_editor):
|
||||
Product = apps.get_model("api", "Product")
|
||||
Founder = apps.get_model("api", "Founder")
|
||||
BlogPost = apps.get_model("api", "BlogPost")
|
||||
Product.objects.filter(slug__in=[r["slug"] for r in PRODUCTS]).delete()
|
||||
Founder.objects.filter(name__in=[r["name"] for r in FOUNDERS]).delete()
|
||||
BlogPost.objects.filter(slug__in=[r["slug"] for r in BLOG_POSTS]).delete()
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [("api", "0001_initial")]
|
||||
operations = [migrations.RunPython(seed, unseed)]
|
||||
0
backend/api/migrations/__init__.py
Normal file
0
backend/api/migrations/__init__.py
Normal file
BIN
backend/api/migrations/__pycache__/0001_initial.cpython-310.pyc
Normal file
BIN
backend/api/migrations/__pycache__/0001_initial.cpython-310.pyc
Normal file
Binary file not shown.
Binary file not shown.
BIN
backend/api/migrations/__pycache__/__init__.cpython-310.pyc
Normal file
BIN
backend/api/migrations/__pycache__/__init__.cpython-310.pyc
Normal file
Binary file not shown.
200
backend/api/models.py
Normal file
200
backend/api/models.py
Normal file
@@ -0,0 +1,200 @@
|
||||
"""Domain models for the RisingCompute marketing site."""
|
||||
from __future__ import annotations
|
||||
|
||||
from django.db import models
|
||||
from django.utils import timezone
|
||||
from django.utils.text import slugify
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------- #
|
||||
# Content (curated by the team in the admin)
|
||||
# --------------------------------------------------------------------------- #
|
||||
class Product(models.Model):
|
||||
"""An IP core / product line shown on the marketing site."""
|
||||
|
||||
CATEGORY_CHOICES = [
|
||||
("ai", "AI Inference"),
|
||||
("security", "Cybersecurity"),
|
||||
("comms", "Communication Protocol"),
|
||||
("asic", "Custom ASIC Services"),
|
||||
("other", "Other"),
|
||||
]
|
||||
|
||||
slug = models.SlugField(unique=True, max_length=80)
|
||||
name = models.CharField(max_length=120)
|
||||
category = models.CharField(max_length=20, choices=CATEGORY_CHOICES)
|
||||
tagline = models.CharField(max_length=200)
|
||||
summary = models.TextField(
|
||||
help_text="2–3 sentence overview shown on the products grid."
|
||||
)
|
||||
description = models.TextField(
|
||||
help_text="Long-form description shown on the product detail page (markdown)."
|
||||
)
|
||||
benefits = models.JSONField(
|
||||
default=list,
|
||||
blank=True,
|
||||
help_text='List of benefit strings. Example: ["High throughput per watt", "INT8/INT4"].',
|
||||
)
|
||||
features = models.JSONField(default=list, blank=True)
|
||||
spec_table = models.JSONField(
|
||||
default=list,
|
||||
blank=True,
|
||||
help_text='List of {"label": "...", "value": "..."} pairs for the spec table.',
|
||||
)
|
||||
primary_cta_label = models.CharField(max_length=60, default="Request evaluation")
|
||||
is_published = models.BooleanField(default=True)
|
||||
sort_order = models.PositiveIntegerField(default=0)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
|
||||
class Meta:
|
||||
ordering = ["sort_order", "name"]
|
||||
|
||||
def __str__(self) -> str:
|
||||
return self.name
|
||||
|
||||
|
||||
class Founder(models.Model):
|
||||
"""Founding-team profile shown on the About page."""
|
||||
|
||||
name = models.CharField(max_length=120)
|
||||
role = models.CharField(max_length=160)
|
||||
domain = models.CharField(
|
||||
max_length=240,
|
||||
help_text="Short description of the technical domain they own.",
|
||||
)
|
||||
bio = models.TextField(help_text="~80-word bio. Markdown allowed.")
|
||||
photo_url = models.URLField(blank=True)
|
||||
linkedin_url = models.URLField(blank=True)
|
||||
sort_order = models.PositiveIntegerField(default=0)
|
||||
is_published = models.BooleanField(default=True)
|
||||
|
||||
class Meta:
|
||||
ordering = ["sort_order", "name"]
|
||||
|
||||
def __str__(self) -> str:
|
||||
return self.name
|
||||
|
||||
|
||||
class BlogPost(models.Model):
|
||||
"""Editorial / engineering blog post."""
|
||||
|
||||
CATEGORY_CHOICES = [
|
||||
("ai", "AI"),
|
||||
("space", "Space"),
|
||||
("robotics", "Robotics"),
|
||||
("engineering", "Engineering"),
|
||||
("company", "Company"),
|
||||
]
|
||||
|
||||
slug = models.SlugField(unique=True, max_length=200)
|
||||
title = models.CharField(max_length=200)
|
||||
excerpt = models.CharField(max_length=300)
|
||||
body = models.TextField(help_text="Markdown.")
|
||||
category = models.CharField(max_length=20, choices=CATEGORY_CHOICES, default="company")
|
||||
author_name = models.CharField(max_length=120)
|
||||
read_time_minutes = models.PositiveIntegerField(default=5)
|
||||
cover_image_url = models.URLField(blank=True)
|
||||
is_published = models.BooleanField(default=True)
|
||||
published_at = models.DateTimeField(default=timezone.now)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
|
||||
class Meta:
|
||||
ordering = ["-published_at"]
|
||||
|
||||
def __str__(self) -> str:
|
||||
return self.title
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
if not self.slug:
|
||||
self.slug = slugify(self.title)[:200]
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
|
||||
class JobOpening(models.Model):
|
||||
"""An open role displayed on the Careers page."""
|
||||
|
||||
LOCATION_CHOICES = [
|
||||
("surat", "Surat, India"),
|
||||
("iist", "STIIC / IIST, Thiruvananthapuram"),
|
||||
("remote", "Remote (India)"),
|
||||
("hybrid", "Hybrid"),
|
||||
]
|
||||
|
||||
slug = models.SlugField(unique=True, max_length=120)
|
||||
title = models.CharField(max_length=160)
|
||||
location = models.CharField(max_length=20, choices=LOCATION_CHOICES, default="surat")
|
||||
employment_type = models.CharField(max_length=40, default="Full-time")
|
||||
description = models.TextField(help_text="Markdown.")
|
||||
is_open = models.BooleanField(default=True)
|
||||
posted_at = models.DateField(default=timezone.now)
|
||||
|
||||
class Meta:
|
||||
ordering = ["-posted_at"]
|
||||
|
||||
def __str__(self) -> str:
|
||||
return self.title
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------- #
|
||||
# Submissions (user input via forms — written by the frontend)
|
||||
# --------------------------------------------------------------------------- #
|
||||
class ContactSubmission(models.Model):
|
||||
INTEREST_CHOICES = [
|
||||
("ai-ip", "AI Inference IP"),
|
||||
("security-ip", "Cybersecurity IP"),
|
||||
("comms-ip", "Communication IP"),
|
||||
("custom-asic", "Custom ASIC"),
|
||||
("careers", "Careers"),
|
||||
("press", "Press"),
|
||||
("other", "Other"),
|
||||
]
|
||||
|
||||
name = models.CharField(max_length=120)
|
||||
email = models.EmailField()
|
||||
company = models.CharField(max_length=160, blank=True)
|
||||
role = models.CharField(max_length=120, blank=True)
|
||||
country = models.CharField(max_length=80, blank=True)
|
||||
interest = models.CharField(max_length=20, choices=INTEREST_CHOICES, default="other")
|
||||
message = models.TextField()
|
||||
referrer = models.CharField(max_length=200, blank=True)
|
||||
user_agent = models.CharField(max_length=400, blank=True)
|
||||
ip_address = models.GenericIPAddressField(null=True, blank=True)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
class Meta:
|
||||
ordering = ["-created_at"]
|
||||
verbose_name = "Contact submission"
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"{self.name} <{self.email}> · {self.get_interest_display()}"
|
||||
|
||||
|
||||
class NewsletterSignup(models.Model):
|
||||
email = models.EmailField(unique=True)
|
||||
source = models.CharField(max_length=120, blank=True, help_text="e.g. footer, blog, contact")
|
||||
confirmed = models.BooleanField(default=False)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
class Meta:
|
||||
ordering = ["-created_at"]
|
||||
|
||||
def __str__(self) -> str:
|
||||
return self.email
|
||||
|
||||
|
||||
class JobApplication(models.Model):
|
||||
name = models.CharField(max_length=120)
|
||||
email = models.EmailField()
|
||||
role_applied_for = models.CharField(max_length=160)
|
||||
portfolio_url = models.URLField(blank=True)
|
||||
message = models.TextField(blank=True)
|
||||
cv = models.FileField(upload_to="applications/%Y/%m/", blank=True, null=True)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
class Meta:
|
||||
ordering = ["-created_at"]
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"{self.name} → {self.role_applied_for}"
|
||||
125
backend/api/serializers.py
Normal file
125
backend/api/serializers.py
Normal file
@@ -0,0 +1,125 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from rest_framework import serializers
|
||||
|
||||
from .models import (
|
||||
BlogPost,
|
||||
ContactSubmission,
|
||||
Founder,
|
||||
JobApplication,
|
||||
JobOpening,
|
||||
NewsletterSignup,
|
||||
Product,
|
||||
)
|
||||
|
||||
|
||||
class ProductSerializer(serializers.ModelSerializer):
|
||||
category_label = serializers.CharField(source="get_category_display", read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = Product
|
||||
fields = [
|
||||
"slug",
|
||||
"name",
|
||||
"category",
|
||||
"category_label",
|
||||
"tagline",
|
||||
"summary",
|
||||
"description",
|
||||
"benefits",
|
||||
"features",
|
||||
"spec_table",
|
||||
"primary_cta_label",
|
||||
]
|
||||
|
||||
|
||||
class FounderSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Founder
|
||||
fields = ["name", "role", "domain", "bio", "photo_url", "linkedin_url"]
|
||||
|
||||
|
||||
class BlogPostListSerializer(serializers.ModelSerializer):
|
||||
category_label = serializers.CharField(source="get_category_display", read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = BlogPost
|
||||
fields = [
|
||||
"slug",
|
||||
"title",
|
||||
"excerpt",
|
||||
"category",
|
||||
"category_label",
|
||||
"author_name",
|
||||
"read_time_minutes",
|
||||
"cover_image_url",
|
||||
"published_at",
|
||||
]
|
||||
|
||||
|
||||
class BlogPostDetailSerializer(BlogPostListSerializer):
|
||||
class Meta(BlogPostListSerializer.Meta):
|
||||
fields = BlogPostListSerializer.Meta.fields + ["body"]
|
||||
|
||||
|
||||
class JobOpeningSerializer(serializers.ModelSerializer):
|
||||
location_label = serializers.CharField(source="get_location_display", read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = JobOpening
|
||||
fields = [
|
||||
"slug",
|
||||
"title",
|
||||
"location",
|
||||
"location_label",
|
||||
"employment_type",
|
||||
"description",
|
||||
"posted_at",
|
||||
]
|
||||
|
||||
|
||||
class ContactSubmissionSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = ContactSubmission
|
||||
fields = [
|
||||
"name",
|
||||
"email",
|
||||
"company",
|
||||
"role",
|
||||
"country",
|
||||
"interest",
|
||||
"message",
|
||||
"referrer",
|
||||
]
|
||||
extra_kwargs = {
|
||||
"name": {"required": True, "allow_blank": False},
|
||||
"email": {"required": True},
|
||||
"message": {"required": True, "allow_blank": False},
|
||||
}
|
||||
|
||||
def validate_message(self, value: str) -> str:
|
||||
if len(value.strip()) < 10:
|
||||
raise serializers.ValidationError(
|
||||
"Please write a few words about what you're looking for."
|
||||
)
|
||||
return value.strip()
|
||||
|
||||
|
||||
class NewsletterSignupSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = NewsletterSignup
|
||||
fields = ["email", "source"]
|
||||
|
||||
def create(self, validated_data):
|
||||
email = validated_data["email"].lower().strip()
|
||||
obj, _ = NewsletterSignup.objects.get_or_create(
|
||||
email=email,
|
||||
defaults={"source": validated_data.get("source", "")},
|
||||
)
|
||||
return obj
|
||||
|
||||
|
||||
class JobApplicationSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = JobApplication
|
||||
fields = ["name", "email", "role_applied_for", "portfolio_url", "message", "cv"]
|
||||
20
backend/api/urls.py
Normal file
20
backend/api/urls.py
Normal file
@@ -0,0 +1,20 @@
|
||||
from django.urls import path
|
||||
|
||||
from . import views
|
||||
|
||||
app_name = "api"
|
||||
|
||||
urlpatterns = [
|
||||
path("health/", views.HealthView.as_view(), name="health"),
|
||||
# content
|
||||
path("products/", views.ProductListView.as_view(), name="product-list"),
|
||||
path("products/<slug:slug>/", views.ProductDetailView.as_view(), name="product-detail"),
|
||||
path("founders/", views.FounderListView.as_view(), name="founder-list"),
|
||||
path("posts/", views.BlogPostListView.as_view(), name="post-list"),
|
||||
path("posts/<slug:slug>/", views.BlogPostDetailView.as_view(), name="post-detail"),
|
||||
path("jobs/", views.JobOpeningListView.as_view(), name="job-list"),
|
||||
# submissions
|
||||
path("contact/", views.ContactSubmissionView.as_view(), name="contact"),
|
||||
path("newsletter/", views.NewsletterSignupView.as_view(), name="newsletter"),
|
||||
path("apply/", views.JobApplicationView.as_view(), name="apply"),
|
||||
]
|
||||
134
backend/api/views.py
Normal file
134
backend/api/views.py
Normal file
@@ -0,0 +1,134 @@
|
||||
"""API endpoints for the RisingCompute marketing site."""
|
||||
from __future__ import annotations
|
||||
|
||||
from django.conf import settings
|
||||
from django.core.mail import send_mail
|
||||
from rest_framework import generics, status
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.views import APIView
|
||||
|
||||
from .models import BlogPost, Founder, JobOpening, Product
|
||||
from .serializers import (
|
||||
BlogPostDetailSerializer,
|
||||
BlogPostListSerializer,
|
||||
ContactSubmissionSerializer,
|
||||
FounderSerializer,
|
||||
JobApplicationSerializer,
|
||||
JobOpeningSerializer,
|
||||
NewsletterSignupSerializer,
|
||||
ProductSerializer,
|
||||
)
|
||||
|
||||
|
||||
def _client_ip(request) -> str | None:
|
||||
forwarded = request.META.get("HTTP_X_FORWARDED_FOR", "")
|
||||
if forwarded:
|
||||
return forwarded.split(",")[0].strip()
|
||||
return request.META.get("REMOTE_ADDR")
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------- #
|
||||
# Read endpoints — content for the public site
|
||||
# --------------------------------------------------------------------------- #
|
||||
class ProductListView(generics.ListAPIView):
|
||||
serializer_class = ProductSerializer
|
||||
queryset = Product.objects.filter(is_published=True)
|
||||
|
||||
|
||||
class ProductDetailView(generics.RetrieveAPIView):
|
||||
serializer_class = ProductSerializer
|
||||
queryset = Product.objects.filter(is_published=True)
|
||||
lookup_field = "slug"
|
||||
|
||||
|
||||
class FounderListView(generics.ListAPIView):
|
||||
serializer_class = FounderSerializer
|
||||
queryset = Founder.objects.filter(is_published=True)
|
||||
|
||||
|
||||
class BlogPostListView(generics.ListAPIView):
|
||||
serializer_class = BlogPostListSerializer
|
||||
queryset = BlogPost.objects.filter(is_published=True)
|
||||
|
||||
|
||||
class BlogPostDetailView(generics.RetrieveAPIView):
|
||||
serializer_class = BlogPostDetailSerializer
|
||||
queryset = BlogPost.objects.filter(is_published=True)
|
||||
lookup_field = "slug"
|
||||
|
||||
|
||||
class JobOpeningListView(generics.ListAPIView):
|
||||
serializer_class = JobOpeningSerializer
|
||||
queryset = JobOpening.objects.filter(is_open=True)
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------- #
|
||||
# Write endpoints — form submissions
|
||||
# --------------------------------------------------------------------------- #
|
||||
class ContactSubmissionView(APIView):
|
||||
"""Accepts a contact / evaluation request from the website."""
|
||||
|
||||
def post(self, request):
|
||||
serializer = ContactSubmissionSerializer(data=request.data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
submission = serializer.save(
|
||||
user_agent=request.META.get("HTTP_USER_AGENT", "")[:400],
|
||||
ip_address=_client_ip(request),
|
||||
)
|
||||
|
||||
try:
|
||||
send_mail(
|
||||
subject=f"[risingcompute.in] New enquiry — {submission.get_interest_display()}",
|
||||
message=(
|
||||
f"From: {submission.name} <{submission.email}>\n"
|
||||
f"Company: {submission.company}\n"
|
||||
f"Role: {submission.role}\n"
|
||||
f"Country: {submission.country}\n"
|
||||
f"Interest: {submission.get_interest_display()}\n"
|
||||
f"Referrer: {submission.referrer}\n\n"
|
||||
f"Message:\n{submission.message}\n"
|
||||
),
|
||||
from_email=settings.DEFAULT_FROM_EMAIL,
|
||||
recipient_list=[settings.NOTIFY_EMAIL_TO],
|
||||
fail_silently=True,
|
||||
)
|
||||
except Exception:
|
||||
# Never let an email hiccup break the submission flow.
|
||||
pass
|
||||
|
||||
return Response(
|
||||
{"ok": True, "message": "Thanks — we'll be in touch shortly."},
|
||||
status=status.HTTP_201_CREATED,
|
||||
)
|
||||
|
||||
|
||||
class NewsletterSignupView(APIView):
|
||||
def post(self, request):
|
||||
serializer = NewsletterSignupSerializer(data=request.data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
serializer.save()
|
||||
return Response(
|
||||
{"ok": True, "message": "You're on the list."},
|
||||
status=status.HTTP_201_CREATED,
|
||||
)
|
||||
|
||||
|
||||
class JobApplicationView(APIView):
|
||||
def post(self, request):
|
||||
serializer = JobApplicationSerializer(data=request.data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
serializer.save()
|
||||
return Response(
|
||||
{"ok": True, "message": "Application received — we'll be in touch."},
|
||||
status=status.HTTP_201_CREATED,
|
||||
)
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------- #
|
||||
# Health check
|
||||
# --------------------------------------------------------------------------- #
|
||||
class HealthView(APIView):
|
||||
"""Simple uptime check used by deploy / monitoring."""
|
||||
|
||||
def get(self, request):
|
||||
return Response({"status": "ok", "service": "risingcompute-api"})
|
||||
20
backend/manage.py
Normal file
20
backend/manage.py
Normal file
@@ -0,0 +1,20 @@
|
||||
#!/usr/bin/env python
|
||||
"""Django's command-line utility for administrative tasks."""
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
def main() -> None:
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "risingcompute.settings")
|
||||
try:
|
||||
from django.core.management import execute_from_command_line
|
||||
except ImportError as exc:
|
||||
raise ImportError(
|
||||
"Couldn't import Django. Is it installed and on PYTHONPATH? "
|
||||
"Did you forget to activate the virtualenv?"
|
||||
) from exc
|
||||
execute_from_command_line(sys.argv)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
8
backend/requirements.txt
Normal file
8
backend/requirements.txt
Normal file
@@ -0,0 +1,8 @@
|
||||
Django==5.0.6
|
||||
djangorestframework==3.15.1
|
||||
django-cors-headers==4.3.1
|
||||
psycopg[binary]==3.1.18
|
||||
python-decouple==3.8
|
||||
dj-database-url==2.1.0
|
||||
gunicorn==22.0.0
|
||||
whitenoise==6.6.0
|
||||
0
backend/risingcompute/__init__.py
Normal file
0
backend/risingcompute/__init__.py
Normal file
BIN
backend/risingcompute/__pycache__/__init__.cpython-310.pyc
Normal file
BIN
backend/risingcompute/__pycache__/__init__.cpython-310.pyc
Normal file
Binary file not shown.
BIN
backend/risingcompute/__pycache__/settings.cpython-310.pyc
Normal file
BIN
backend/risingcompute/__pycache__/settings.cpython-310.pyc
Normal file
Binary file not shown.
BIN
backend/risingcompute/__pycache__/urls.cpython-310.pyc
Normal file
BIN
backend/risingcompute/__pycache__/urls.cpython-310.pyc
Normal file
Binary file not shown.
7
backend/risingcompute/asgi.py
Normal file
7
backend/risingcompute/asgi.py
Normal file
@@ -0,0 +1,7 @@
|
||||
import os
|
||||
|
||||
from django.core.asgi import get_asgi_application
|
||||
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "risingcompute.settings")
|
||||
|
||||
application = get_asgi_application()
|
||||
161
backend/risingcompute/settings.py
Normal file
161
backend/risingcompute/settings.py
Normal file
@@ -0,0 +1,161 @@
|
||||
"""
|
||||
Django settings for the RisingCompute marketing site.
|
||||
|
||||
All sensitive / environment-specific values come from a `.env` file
|
||||
(see `.env.example`) and are loaded via python-decouple.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
import dj_database_url
|
||||
from decouple import Csv, config
|
||||
|
||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||
|
||||
# --------------------------------------------------------------------------- #
|
||||
# Core
|
||||
# --------------------------------------------------------------------------- #
|
||||
SECRET_KEY = config("DJANGO_SECRET_KEY", default="dev-insecure-key-change-me")
|
||||
DEBUG = config("DJANGO_DEBUG", default=False, cast=bool)
|
||||
ALLOWED_HOSTS = config(
|
||||
"DJANGO_ALLOWED_HOSTS",
|
||||
default="localhost,127.0.0.1",
|
||||
cast=Csv(),
|
||||
)
|
||||
|
||||
INSTALLED_APPS = [
|
||||
"django.contrib.admin",
|
||||
"django.contrib.auth",
|
||||
"django.contrib.contenttypes",
|
||||
"django.contrib.sessions",
|
||||
"django.contrib.messages",
|
||||
"django.contrib.staticfiles",
|
||||
# third-party
|
||||
"rest_framework",
|
||||
"corsheaders",
|
||||
# local
|
||||
"api",
|
||||
]
|
||||
|
||||
MIDDLEWARE = [
|
||||
"django.middleware.security.SecurityMiddleware",
|
||||
"whitenoise.middleware.WhiteNoiseMiddleware",
|
||||
"corsheaders.middleware.CorsMiddleware",
|
||||
"django.contrib.sessions.middleware.SessionMiddleware",
|
||||
"django.middleware.common.CommonMiddleware",
|
||||
"django.middleware.csrf.CsrfViewMiddleware",
|
||||
"django.contrib.auth.middleware.AuthenticationMiddleware",
|
||||
"django.contrib.messages.middleware.MessageMiddleware",
|
||||
"django.middleware.clickjacking.XFrameOptionsMiddleware",
|
||||
]
|
||||
|
||||
ROOT_URLCONF = "risingcompute.urls"
|
||||
|
||||
TEMPLATES = [
|
||||
{
|
||||
"BACKEND": "django.template.backends.django.DjangoTemplates",
|
||||
"DIRS": [],
|
||||
"APP_DIRS": True,
|
||||
"OPTIONS": {
|
||||
"context_processors": [
|
||||
"django.template.context_processors.debug",
|
||||
"django.template.context_processors.request",
|
||||
"django.contrib.auth.context_processors.auth",
|
||||
"django.contrib.messages.context_processors.messages",
|
||||
],
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
WSGI_APPLICATION = "risingcompute.wsgi.application"
|
||||
|
||||
# --------------------------------------------------------------------------- #
|
||||
# Database (PostgreSQL via DATABASE_URL — see DATABASE_SETUP.md)
|
||||
# --------------------------------------------------------------------------- #
|
||||
DATABASES = {
|
||||
"default": dj_database_url.config(
|
||||
default=config(
|
||||
"DATABASE_URL",
|
||||
default="postgres://risingcompute:risingcompute@127.0.0.1:5432/risingcompute",
|
||||
),
|
||||
conn_max_age=600,
|
||||
),
|
||||
}
|
||||
|
||||
# --------------------------------------------------------------------------- #
|
||||
# Auth, i18n, static
|
||||
# --------------------------------------------------------------------------- #
|
||||
AUTH_PASSWORD_VALIDATORS = [
|
||||
{"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator"},
|
||||
{"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator"},
|
||||
{"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator"},
|
||||
{"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator"},
|
||||
]
|
||||
|
||||
LANGUAGE_CODE = "en-in"
|
||||
TIME_ZONE = "Asia/Kolkata"
|
||||
USE_I18N = True
|
||||
USE_TZ = True
|
||||
|
||||
STATIC_URL = "static/"
|
||||
STATIC_ROOT = BASE_DIR / "staticfiles"
|
||||
STATICFILES_STORAGE = "whitenoise.storage.CompressedManifestStaticFilesStorage"
|
||||
|
||||
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
|
||||
|
||||
# --------------------------------------------------------------------------- #
|
||||
# DRF
|
||||
# --------------------------------------------------------------------------- #
|
||||
REST_FRAMEWORK = {
|
||||
"DEFAULT_RENDERER_CLASSES": [
|
||||
"rest_framework.renderers.JSONRenderer",
|
||||
],
|
||||
"DEFAULT_PARSER_CLASSES": [
|
||||
"rest_framework.parsers.JSONParser",
|
||||
"rest_framework.parsers.MultiPartParser",
|
||||
"rest_framework.parsers.FormParser",
|
||||
],
|
||||
"DEFAULT_THROTTLE_CLASSES": [
|
||||
"rest_framework.throttling.AnonRateThrottle",
|
||||
],
|
||||
"DEFAULT_THROTTLE_RATES": {
|
||||
"anon": "30/hour",
|
||||
"user": "120/hour",
|
||||
},
|
||||
}
|
||||
|
||||
# --------------------------------------------------------------------------- #
|
||||
# CORS — Vue dev server on :5173, production domain
|
||||
# --------------------------------------------------------------------------- #
|
||||
CORS_ALLOWED_ORIGINS = config(
|
||||
"CORS_ALLOWED_ORIGINS",
|
||||
default="http://localhost:5173,http://127.0.0.1:5173",
|
||||
cast=Csv(),
|
||||
)
|
||||
CORS_ALLOW_CREDENTIALS = True
|
||||
|
||||
# --------------------------------------------------------------------------- #
|
||||
# Email (form submission notifications)
|
||||
# --------------------------------------------------------------------------- #
|
||||
NOTIFY_EMAIL_TO = config("NOTIFY_EMAIL_TO", default="contact@risingcompute.in")
|
||||
DEFAULT_FROM_EMAIL = config(
|
||||
"DEFAULT_FROM_EMAIL", default="noreply@risingcompute.in"
|
||||
)
|
||||
EMAIL_BACKEND = config(
|
||||
"EMAIL_BACKEND",
|
||||
default="django.core.mail.backends.console.EmailBackend",
|
||||
)
|
||||
|
||||
# --------------------------------------------------------------------------- #
|
||||
# Security hardening for production
|
||||
# --------------------------------------------------------------------------- #
|
||||
if not DEBUG:
|
||||
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
|
||||
SECURE_SSL_REDIRECT = True
|
||||
SESSION_COOKIE_SECURE = True
|
||||
CSRF_COOKIE_SECURE = True
|
||||
SECURE_HSTS_SECONDS = 60 * 60 * 24 * 30 # 30 days; raise to 1 year once stable
|
||||
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
|
||||
SECURE_CONTENT_TYPE_NOSNIFF = True
|
||||
X_FRAME_OPTIONS = "DENY"
|
||||
7
backend/risingcompute/urls.py
Normal file
7
backend/risingcompute/urls.py
Normal file
@@ -0,0 +1,7 @@
|
||||
from django.contrib import admin
|
||||
from django.urls import include, path
|
||||
|
||||
urlpatterns = [
|
||||
path("admin/", admin.site.urls),
|
||||
path("api/", include("api.urls")),
|
||||
]
|
||||
7
backend/risingcompute/wsgi.py
Normal file
7
backend/risingcompute/wsgi.py
Normal file
@@ -0,0 +1,7 @@
|
||||
import os
|
||||
|
||||
from django.core.wsgi import get_wsgi_application
|
||||
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "risingcompute.settings")
|
||||
|
||||
application = get_wsgi_application()
|
||||
0
backend/verify.sqlite3
Normal file
0
backend/verify.sqlite3
Normal file
667
design-document.md
Normal file
667
design-document.md
Normal file
@@ -0,0 +1,667 @@
|
||||
# Website Design Document
|
||||
|
||||
> **How to use this document:** Fill in every section below. Replace the `_[fill in]_` placeholders with your details and tick the checkboxes that apply. Anywhere you see **💡 Recommendation**, that's a suggested default — keep it, edit it, or replace it. The more detail you provide, the closer the final website will match your vision.
|
||||
|
||||
---
|
||||
|
||||
## 1. Project Snapshot
|
||||
|
||||
| Field | Your Answer |
|
||||
|---|---|
|
||||
| **Company name** | _[fill in]_ |
|
||||
| **Legal entity name (if different)** | _[fill in]_ |
|
||||
| **Primary domain** | _[e.g. acme.com]_ |
|
||||
| **Working title for the project** | _[e.g. "Acme Website Redesign 2026"]_ |
|
||||
| **Target launch date** | _[fill in]_ |
|
||||
| **Budget range** | _[fill in]_ |
|
||||
| **Document owner** | _[name + email]_ |
|
||||
| **Last updated** | _[date]_ |
|
||||
|
||||
---
|
||||
|
||||
## 2. Company Overview
|
||||
|
||||
### 2.1 Who we are
|
||||
- **What we do (one sentence):** _[fill in]_
|
||||
- **Tagline / one-liner:** _[fill in]_
|
||||
- **Elevator pitch (3–4 sentences):** _[fill in]_
|
||||
|
||||
### 2.2 Mission, vision, values
|
||||
- **Mission:** _[Why we exist]_
|
||||
- **Vision:** _[Where we're going]_
|
||||
- **Core values:** _[List 3–6, e.g. Honesty, Craft, Speed]_
|
||||
|
||||
### 2.3 Company facts
|
||||
- **Founded:** _[year]_
|
||||
- **Headquarters:** _[city, country]_
|
||||
- **Other offices / coverage areas:** _[fill in]_
|
||||
- **Team size:** _[fill in]_
|
||||
- **Industry / sector:** _[fill in]_
|
||||
- **Stage:** _[ ] Pre-revenue [ ] Early revenue [ ] Growth [ ] Established_
|
||||
|
||||
### 2.4 Our story
|
||||
_Brief origin story — why the company was started, key milestones, what makes the journey notable. 100–250 words._
|
||||
|
||||
> _[fill in]_
|
||||
|
||||
### 2.5 Key milestones / achievements
|
||||
- _[Milestone + year]_
|
||||
- _[Award / press mention]_
|
||||
- _[Notable client or partnership]_
|
||||
|
||||
---
|
||||
|
||||
## 3. Target Audience
|
||||
|
||||
### 3.1 Primary audience
|
||||
- **Who they are:** _[e.g. operations managers at 50–500-person SaaS companies]_
|
||||
- **Where they're based:** _[fill in]_
|
||||
- **Age range:** _[fill in]_
|
||||
- **Job titles / roles:** _[fill in]_
|
||||
- **Industries:** _[fill in]_
|
||||
|
||||
### 3.2 Audience personas
|
||||
Define 1–3 personas. Duplicate the block as needed.
|
||||
|
||||
**Persona 1 — _[name, e.g. "Ops Olivia"]_**
|
||||
- Role / background: _[fill in]_
|
||||
- Goals: _[What they want to achieve]_
|
||||
- Pain points: _[What frustrates them today]_
|
||||
- What they need from our site: _[e.g. proof we can scale, pricing clarity, a demo]_
|
||||
- Triggers to convert: _[fill in]_
|
||||
|
||||
**Persona 2 — _[name]_**
|
||||
- _[same fields]_
|
||||
|
||||
### 3.3 What we want visitors to do
|
||||
Rank in priority order (1 = most important):
|
||||
- [ ] Request a demo / consultation
|
||||
- [ ] Buy a product or service
|
||||
- [ ] Sign up for a free trial or newsletter
|
||||
- [ ] Download a resource (whitepaper, case study)
|
||||
- [ ] Contact sales
|
||||
- [ ] Apply for a job
|
||||
- [ ] Learn / build brand awareness
|
||||
- [ ] Other: _[fill in]_
|
||||
|
||||
---
|
||||
|
||||
## 4. Goals, KPIs & Success Metrics
|
||||
|
||||
### 4.1 Business goals for this website
|
||||
1. _[e.g. Generate 50 qualified leads per month]_
|
||||
2. _[fill in]_
|
||||
3. _[fill in]_
|
||||
|
||||
### 4.2 Measurable KPIs
|
||||
| KPI | Current baseline | 6-month target |
|
||||
|---|---|---|
|
||||
| Monthly unique visitors | _[fill in]_ | _[fill in]_ |
|
||||
| Conversion rate (visit → lead) | _[fill in]_ | _[fill in]_ |
|
||||
| Average session duration | _[fill in]_ | _[fill in]_ |
|
||||
| Demo / contact form submissions / month | _[fill in]_ | _[fill in]_ |
|
||||
| Organic search traffic | _[fill in]_ | _[fill in]_ |
|
||||
|
||||
### 4.3 What "success" looks like 12 months after launch
|
||||
> _[fill in]_
|
||||
|
||||
---
|
||||
|
||||
## 5. Competitor & Inspiration Landscape
|
||||
|
||||
### 5.1 Direct competitors
|
||||
| Competitor | URL | What they do well | Where they fall short |
|
||||
|---|---|---|---|
|
||||
| _[Name]_ | _[URL]_ | _[fill in]_ | _[fill in]_ |
|
||||
| _[Name]_ | _[URL]_ | _[fill in]_ | _[fill in]_ |
|
||||
| _[Name]_ | _[URL]_ | _[fill in]_ | _[fill in]_ |
|
||||
|
||||
### 5.2 Sites we love (any industry)
|
||||
List 3–5 sites whose design, copy, or feel you admire. Note **why**.
|
||||
- _[URL]_ — _[what you like: typography, color, motion, copywriting tone, layout, etc.]_
|
||||
- _[URL]_ — _[why]_
|
||||
- _[URL]_ — _[why]_
|
||||
|
||||
### 5.3 Sites we want to look nothing like
|
||||
- _[URL]_ — _[why not]_
|
||||
|
||||
### 5.4 Our differentiators
|
||||
What makes us genuinely different / better? Be specific.
|
||||
1. _[fill in]_
|
||||
2. _[fill in]_
|
||||
3. _[fill in]_
|
||||
|
||||
---
|
||||
|
||||
## 6. Products & Services
|
||||
|
||||
For each offering, fill in the block. Duplicate as needed.
|
||||
|
||||
### Offering 1 — _[name]_
|
||||
- **What it is:** _[fill in]_
|
||||
- **Who it's for:** _[fill in]_
|
||||
- **Key benefits (3–5):** _[fill in]_
|
||||
- **Features / what's included:** _[fill in]_
|
||||
- **Pricing model:** _[ ] Fixed [ ] Tiered [ ] Custom quote [ ] Hidden until contact_
|
||||
- **Price points (if shown):** _[fill in]_
|
||||
- **Primary CTA:** _[e.g. "Book a demo", "Get a quote"]_
|
||||
- **Supporting proof:** _[case studies, stats, testimonials to attach]_
|
||||
|
||||
### Offering 2 — _[name]_
|
||||
_[same fields]_
|
||||
|
||||
---
|
||||
|
||||
## 7. Brand Identity
|
||||
|
||||
### 7.1 Logo
|
||||
- [ ] We have a finalized logo (attach: _[file path / link]_)
|
||||
- [ ] We have a logo but it needs cleanup
|
||||
- [ ] We need a logo designed
|
||||
|
||||
### 7.2 Color palette
|
||||
List hex codes. If you don't have a palette yet, describe the mood and we'll propose one.
|
||||
|
||||
| Role | Color | Hex | Notes |
|
||||
|---|---|---|---|
|
||||
| Primary | _[e.g. Deep blue]_ | `#______` | Used for CTAs, links |
|
||||
| Secondary | _[fill in]_ | `#______` | _[fill in]_ |
|
||||
| Accent | _[fill in]_ | `#______` | Used sparingly for emphasis |
|
||||
| Neutral dark | _[fill in]_ | `#______` | Body text |
|
||||
| Neutral light | _[fill in]_ | `#______` | Backgrounds |
|
||||
| Success / Warning / Error | _[fill in]_ | `#______` | UI states |
|
||||
|
||||
> **💡 Recommendation:** Pick one primary brand color, one accent, and a neutral scale (5–7 grays). Avoid more than 3 saturated colors — it gets noisy fast.
|
||||
|
||||
### 7.3 Typography
|
||||
- **Heading font:** _[e.g. Inter / Custom / "open to suggestion"]_
|
||||
- **Body font:** _[fill in]_
|
||||
- **Monospace (if used):** _[fill in]_
|
||||
|
||||
> **💡 Recommendation:** Use a pairing like **Inter** (headings + body) or **Fraunces + Inter** (editorial feel + clean body). Both are free, web-optimized, and load fast.
|
||||
|
||||
### 7.4 Imagery & illustration style
|
||||
- [ ] Photography — real, candid people in our offices
|
||||
- [ ] Photography — stock (specify style: _[bright & airy / moody / corporate / lifestyle]_)
|
||||
- [ ] Custom illustration (style: _[fill in]_)
|
||||
- [ ] 3D renders
|
||||
- [ ] Icon-led, minimal imagery
|
||||
- [ ] Mix — describe: _[fill in]_
|
||||
|
||||
### 7.5 Voice & tone
|
||||
Pick 3–5 adjectives that describe how we sound:
|
||||
- [ ] Authoritative [ ] Friendly [ ] Playful [ ] Technical [ ] Aspirational
|
||||
- [ ] Witty [ ] Calm [ ] Direct [ ] Warm [ ] Bold
|
||||
- Other: _[fill in]_
|
||||
|
||||
**Example phrases we'd say:**
|
||||
> _[2–3 sample sentences in our voice]_
|
||||
|
||||
**Example phrases we'd never say:**
|
||||
> _[fill in]_
|
||||
|
||||
### 7.6 Existing brand assets
|
||||
- [ ] Brand guidelines doc — link: _[fill in]_
|
||||
- [ ] Logo files (SVG / PNG)
|
||||
- [ ] Photography library
|
||||
- [ ] Existing website copy worth keeping
|
||||
|
||||
---
|
||||
|
||||
## 8. Site Structure (Information Architecture)
|
||||
|
||||
### 8.1 Sitemap
|
||||
Tick the pages you want. Add custom ones at the bottom.
|
||||
|
||||
- [ ] **Home**
|
||||
- [ ] **About** — story, team, values
|
||||
- [ ] Team / Leadership sub-page
|
||||
- [ ] Careers sub-page
|
||||
- [ ] **Services** / **Products** — overview
|
||||
- [ ] Individual service / product pages (one per offering)
|
||||
- [ ] **Case Studies** / **Work** / **Portfolio**
|
||||
- [ ] Individual case study pages
|
||||
- [ ] **Pricing**
|
||||
- [ ] **Blog** / **Resources** / **Insights**
|
||||
- [ ] Article template
|
||||
- [ ] Category pages
|
||||
- [ ] **FAQ**
|
||||
- [ ] **Contact**
|
||||
- [ ] **Book a demo** / **Get a quote** (landing page)
|
||||
- [ ] **Press / News**
|
||||
- [ ] **Partners**
|
||||
- [ ] **404 page**
|
||||
- [ ] **Thank-you pages** (post-form)
|
||||
- [ ] **Privacy Policy** _(required)_
|
||||
- [ ] **Terms of Service** _(required)_
|
||||
- [ ] **Cookie Policy** _(if EU/UK visitors)_
|
||||
- Custom: _[fill in]_
|
||||
|
||||
### 8.2 Primary navigation
|
||||
List the top-nav items in order:
|
||||
1. _[fill in]_
|
||||
2. _[fill in]_
|
||||
3. _[fill in]_
|
||||
4. _[fill in]_
|
||||
5. **CTA button** — label: _[e.g. "Book a demo"]_
|
||||
|
||||
### 8.3 Footer
|
||||
- [ ] Mini sitemap
|
||||
- [ ] Contact info (address, phone, email)
|
||||
- [ ] Social links: _[which platforms]_
|
||||
- [ ] Newsletter signup
|
||||
- [ ] Legal links (Privacy, Terms, Cookies)
|
||||
- [ ] Company registration number / VAT (if required)
|
||||
- [ ] Industry certifications / logos
|
||||
|
||||
---
|
||||
|
||||
## 9. Page-by-Page Content Brief
|
||||
|
||||
### 9.1 Home
|
||||
- **Hero headline (max 10 words):** _[fill in]_
|
||||
- **Hero sub-headline (1–2 sentences):** _[fill in]_
|
||||
- **Primary CTA:** _[label + destination]_
|
||||
- **Secondary CTA:** _[label + destination]_
|
||||
- **Sections to include (in order):**
|
||||
- [ ] Hero with visual
|
||||
- [ ] Social proof bar (client logos / press)
|
||||
- [ ] What we do (3–4 service highlights)
|
||||
- [ ] How it works / process
|
||||
- [ ] Why us / differentiators
|
||||
- [ ] Featured case study or proof point
|
||||
- [ ] Testimonials
|
||||
- [ ] Stats / metrics
|
||||
- [ ] Recent blog posts
|
||||
- [ ] Final CTA block
|
||||
- **Key visuals needed:** _[fill in]_
|
||||
|
||||
### 9.2 About
|
||||
- Origin story: _[link to §2.4 or expand here]_
|
||||
- Team intro: _[ ] full team grid [ ] leadership only [ ] no photos_
|
||||
- Values block: _[link to §2.2]_
|
||||
- Office / culture photos: _[ ] yes [ ] no_
|
||||
- Press / awards row: _[ ] yes [ ] no_
|
||||
|
||||
### 9.3 Services / Products
|
||||
For each offering, one page with:
|
||||
- Hero with the offering name + one-liner
|
||||
- The problem it solves
|
||||
- How it works (steps or features)
|
||||
- What's included
|
||||
- Pricing or "request a quote"
|
||||
- FAQs specific to this offering
|
||||
- CTA
|
||||
|
||||
### 9.4 Case Studies / Work
|
||||
- Number of case studies at launch: _[fill in]_
|
||||
- Template per case study:
|
||||
- Client + industry
|
||||
- Challenge (the problem)
|
||||
- Approach (what we did)
|
||||
- Outcome (metrics, quotes)
|
||||
- Visuals: _[before/after, screenshots, photos]_
|
||||
|
||||
### 9.5 Pricing _(if applicable)_
|
||||
- [ ] Show full pricing
|
||||
- [ ] Show tiers, hide exact numbers
|
||||
- [ ] "Contact us" only
|
||||
- Tiers: _[list each tier with price + what's included]_
|
||||
- Add-ons: _[fill in]_
|
||||
|
||||
### 9.6 Blog / Resources
|
||||
- Launch with how many posts? _[fill in]_
|
||||
- Categories: _[fill in]_
|
||||
- Authors shown? _[ ] yes [ ] no_
|
||||
- Comments enabled? _[ ] yes [ ] no_
|
||||
- Newsletter signup on every post? _[ ] yes [ ] no_
|
||||
|
||||
### 9.7 Contact
|
||||
- [ ] Contact form (fields: _[name, email, company, message, ...]_)
|
||||
- [ ] Direct email
|
||||
- [ ] Phone number
|
||||
- [ ] Physical address + map
|
||||
- [ ] Office hours
|
||||
- [ ] Calendly / booking link
|
||||
- [ ] Live chat widget
|
||||
|
||||
### 9.8 Other pages
|
||||
_[Add custom briefs as needed]_
|
||||
|
||||
---
|
||||
|
||||
## 10. Features & Functionality
|
||||
|
||||
Tick everything the site needs:
|
||||
|
||||
**Lead capture & forms**
|
||||
- [ ] Contact form
|
||||
- [ ] Demo request form
|
||||
- [ ] Quote / estimate form
|
||||
- [ ] Newsletter signup
|
||||
- [ ] Gated content (downloads behind email)
|
||||
- [ ] Multi-step / progressive forms
|
||||
|
||||
**Content & engagement**
|
||||
- [ ] Blog with categories & tags
|
||||
- [ ] Search
|
||||
- [ ] Filtering on listings (case studies, blog)
|
||||
- [ ] Comments
|
||||
- [ ] Social share buttons
|
||||
- [ ] RSS feed
|
||||
|
||||
**Booking & scheduling**
|
||||
- [ ] Calendly / Cal.com embed
|
||||
- [ ] Custom booking flow
|
||||
- [ ] Event RSVPs
|
||||
|
||||
**Commerce / payments**
|
||||
- [ ] One-off product checkout
|
||||
- [ ] Subscription billing (Stripe)
|
||||
- [ ] Invoice / quote generation
|
||||
|
||||
**Authentication / portal**
|
||||
- [ ] Client login area
|
||||
- [ ] Account dashboard
|
||||
- [ ] File / document sharing
|
||||
|
||||
**Interactivity**
|
||||
- [ ] Animations / scroll effects
|
||||
- [ ] Video backgrounds
|
||||
- [ ] Interactive product tour
|
||||
- [ ] Calculator / configurator
|
||||
- [ ] Live chat (Intercom / Crisp / HubSpot)
|
||||
- [ ] Chatbot (AI / rules-based)
|
||||
|
||||
**Localization**
|
||||
- [ ] Multi-language: _[which languages]_
|
||||
- [ ] Multi-currency
|
||||
- [ ] Region-aware content
|
||||
|
||||
**Other:** _[fill in]_
|
||||
|
||||
---
|
||||
|
||||
## 11. Design Direction
|
||||
|
||||
### 11.1 Mood
|
||||
Pick the words that fit. Strike through ones that don't.
|
||||
Minimalist · Bold · Elegant · Playful · Editorial · Corporate · Warm · Futuristic · Premium · Approachable · Technical · Human · Spacious · Dense · Quiet · Energetic
|
||||
|
||||
**Top 3 for our brand:** _[fill in]_
|
||||
|
||||
### 11.2 Layout preferences
|
||||
- **Density:** _[ ] Spacious / lots of whitespace [ ] Balanced [ ] Dense / information-rich_
|
||||
- **Width:** _[ ] Full-bleed / edge-to-edge [ ] Contained (max ~1200–1400px)_
|
||||
- **Page rhythm:** _[ ] One idea per scroll-section [ ] Multi-column / magazine-style_
|
||||
|
||||
### 11.3 Motion & interactivity
|
||||
- [ ] No motion — fast and static
|
||||
- [ ] Subtle (fade-ins, hover states)
|
||||
- [ ] Moderate (scroll-triggered reveals, parallax)
|
||||
- [ ] Rich (custom animations, WebGL, video)
|
||||
|
||||
### 11.4 Devices to prioritize
|
||||
- [ ] Mobile-first (most traffic on phones)
|
||||
- [ ] Desktop-first (B2B sales context)
|
||||
- [ ] Equal weight
|
||||
- **Browser support:** _[modern evergreen / IE11 / specify]_
|
||||
|
||||
---
|
||||
|
||||
## 12. Tech Stack
|
||||
|
||||
### 12.1 Frontend framework
|
||||
- [ ] **Next.js (React)** — 💡 Recommended for marketing sites that need flexibility, blog, and excellent SEO
|
||||
- [ ] **Astro** — 💡 Recommended for content-heavy, mostly-static sites; fastest performance
|
||||
- [ ] **SvelteKit** — modern, lean, great DX
|
||||
- [ ] **Plain HTML/CSS/JS** — simplest, for very small sites
|
||||
- [ ] Other: _[fill in]_
|
||||
|
||||
### 12.2 Styling
|
||||
- [ ] **Tailwind CSS** — 💡 Recommended, fastest to iterate
|
||||
- [ ] CSS Modules
|
||||
- [ ] Styled Components / Emotion
|
||||
- [ ] Vanilla CSS
|
||||
- [ ] Other: _[fill in]_
|
||||
|
||||
### 12.3 CMS / Content management
|
||||
Where will marketing edit content?
|
||||
- [ ] **Sanity** — 💡 Recommended; flexible schemas, great editor UX
|
||||
- [ ] **Contentful** — enterprise-friendly, more expensive
|
||||
- [ ] **Strapi** — self-hosted, open source
|
||||
- [ ] **WordPress (headless)** — familiar editor, huge ecosystem
|
||||
- [ ] **Markdown in the repo** — for tech-savvy teams, no CMS overhead
|
||||
- [ ] **Notion as CMS** — easy for non-technical teams
|
||||
- [ ] No CMS — developers update content directly
|
||||
- [ ] Other: _[fill in]_
|
||||
|
||||
### 12.4 Hosting & deployment
|
||||
- [ ] **Vercel** — 💡 Recommended for Next.js; preview URLs, zero config
|
||||
- [ ] **Netlify** — great for Astro / static sites
|
||||
- [ ] **Cloudflare Pages** — fast, generous free tier
|
||||
- [ ] AWS / GCP / Azure — if existing cloud commitments
|
||||
- [ ] Other: _[fill in]_
|
||||
|
||||
### 12.5 Domain & DNS
|
||||
- **Existing domain:** _[fill in]_
|
||||
- **Registrar:** _[fill in]_
|
||||
- **DNS provider:** _[ ] Same as registrar [ ] Cloudflare [ ] Other_
|
||||
- **Email hosting:** _[Google Workspace / Microsoft 365 / other]_
|
||||
|
||||
### 12.6 Forms backend
|
||||
- [ ] **HubSpot Forms** — if using HubSpot CRM
|
||||
- [ ] **Formspree / Basin** — simple email-based handling
|
||||
- [ ] **Custom API + database**
|
||||
- [ ] CMS-native (Sanity, etc.)
|
||||
|
||||
### 12.7 Repository & CI
|
||||
- **Code host:** _[ ] GitHub [ ] GitLab [ ] Bitbucket_
|
||||
- **CI/CD:** _[ ] Vercel/Netlify built-in [ ] GitHub Actions [ ] Other_
|
||||
|
||||
---
|
||||
|
||||
## 13. Integrations
|
||||
|
||||
Tick everything that needs to talk to the website.
|
||||
|
||||
**Analytics & attribution**
|
||||
- [ ] Google Analytics 4
|
||||
- [ ] Plausible / Fathom (privacy-friendly) — 💡 Recommended if GDPR matters
|
||||
- [ ] PostHog (product analytics)
|
||||
- [ ] Hotjar / Microsoft Clarity (heatmaps & recordings)
|
||||
|
||||
**Marketing & CRM**
|
||||
- [ ] HubSpot
|
||||
- [ ] Salesforce
|
||||
- [ ] Pipedrive
|
||||
- [ ] Mailchimp / ConvertKit / Beehiiv (newsletter)
|
||||
- [ ] Customer.io / Klaviyo
|
||||
|
||||
**Communication**
|
||||
- [ ] Slack notifications on form submits
|
||||
- [ ] Intercom / Crisp / HelpScout (live chat / helpdesk)
|
||||
|
||||
**Booking & payments**
|
||||
- [ ] Calendly / Cal.com
|
||||
- [ ] Stripe
|
||||
- [ ] PayPal
|
||||
|
||||
**Other**
|
||||
- [ ] Algolia / Meilisearch (search)
|
||||
- [ ] Tag manager (GTM)
|
||||
- [ ] reCAPTCHA / Turnstile (form spam)
|
||||
- Custom API: _[fill in]_
|
||||
|
||||
---
|
||||
|
||||
## 14. SEO & Content Strategy
|
||||
|
||||
### 14.1 Target keywords
|
||||
List 5–15 keywords / phrases you want to rank for.
|
||||
1. _[fill in]_
|
||||
2. _[fill in]_
|
||||
3. _[fill in]_
|
||||
|
||||
### 14.2 Per-page meta
|
||||
We'll fill these per page during build, but flag any **must-have** titles or descriptions here.
|
||||
- _[fill in]_
|
||||
|
||||
### 14.3 Structured data
|
||||
- [ ] Organization schema
|
||||
- [ ] LocalBusiness schema (if relevant)
|
||||
- [ ] Article schema (blog)
|
||||
- [ ] FAQ schema
|
||||
- [ ] Product / Service schema
|
||||
- [ ] BreadcrumbList
|
||||
|
||||
### 14.4 Redirects / migration
|
||||
If replacing an existing site:
|
||||
- [ ] Old sitemap to preserve: _[link]_
|
||||
- [ ] 301 redirect map needed: _[ ] yes [ ] no_
|
||||
- [ ] URL structure changing? _[fill in]_
|
||||
|
||||
### 14.5 Content production
|
||||
- Who writes the copy? _[ ] We will [ ] You / your team [ ] External copywriter_
|
||||
- Who edits the blog post-launch? _[fill in]_
|
||||
- Cadence: _[posts per month]_
|
||||
|
||||
---
|
||||
|
||||
## 15. Accessibility, Compliance & Legal
|
||||
|
||||
### 15.1 Accessibility
|
||||
- [ ] WCAG 2.1 **AA** target — 💡 Recommended baseline
|
||||
- [ ] WCAG 2.1 AAA (stricter, for public-sector / health)
|
||||
- [ ] No specific target
|
||||
|
||||
### 15.2 Privacy & data
|
||||
- **Visitors from EU/UK?** _[ ] yes [ ] no_ → if yes, GDPR applies
|
||||
- **Visitors from California?** _[ ] yes [ ] no_ → if yes, CCPA applies
|
||||
- [ ] Cookie consent banner needed
|
||||
- [ ] Privacy policy already exists — link: _[fill in]_
|
||||
- [ ] Need privacy policy written
|
||||
- [ ] Terms of service already exists — link: _[fill in]_
|
||||
- [ ] Need ToS written
|
||||
- **Data controller / DPO contact:** _[fill in]_
|
||||
|
||||
### 15.3 Industry-specific
|
||||
- [ ] Healthcare (HIPAA) — _[fill in]_
|
||||
- [ ] Finance / banking — _[fill in]_
|
||||
- [ ] Children's products (COPPA)
|
||||
- [ ] Other regulated: _[fill in]_
|
||||
|
||||
---
|
||||
|
||||
## 16. Performance & Quality Bar
|
||||
|
||||
### 16.1 Performance targets
|
||||
- [ ] **Lighthouse score 90+** on mobile (performance, accessibility, SEO) — 💡 Recommended
|
||||
- [ ] **LCP < 2.5s**, **CLS < 0.1**, **INP < 200ms** (Core Web Vitals "good")
|
||||
- [ ] Page weight under _[e.g. 1 MB]_ on landing pages
|
||||
|
||||
### 16.2 Browser support
|
||||
- Modern Chrome / Safari / Firefox / Edge (last 2 versions) — 💡 Recommended default
|
||||
- [ ] Need IE11 / older support: _[describe]_
|
||||
|
||||
### 16.3 Quality assurance
|
||||
- [ ] Cross-browser testing
|
||||
- [ ] Mobile device testing (iOS Safari, Android Chrome)
|
||||
- [ ] Accessibility audit (manual + automated)
|
||||
- [ ] Performance audit (Lighthouse + WebPageTest)
|
||||
- [ ] SEO audit pre-launch
|
||||
|
||||
---
|
||||
|
||||
## 17. Timeline & Milestones
|
||||
|
||||
| Milestone | Target date | Owner |
|
||||
|---|---|---|
|
||||
| Design document signed off | _[date]_ | _[name]_ |
|
||||
| Wireframes approved | _[date]_ | _[name]_ |
|
||||
| Visual designs approved | _[date]_ | _[name]_ |
|
||||
| Content delivered | _[date]_ | _[name]_ |
|
||||
| Development complete | _[date]_ | _[name]_ |
|
||||
| QA / UAT | _[date]_ | _[name]_ |
|
||||
| Soft launch / staging review | _[date]_ | _[name]_ |
|
||||
| **Public launch** | _[date]_ | _[name]_ |
|
||||
|
||||
---
|
||||
|
||||
## 18. Budget
|
||||
|
||||
| Bucket | Estimate |
|
||||
|---|---|
|
||||
| Design | _[fill in]_ |
|
||||
| Development | _[fill in]_ |
|
||||
| Copywriting | _[fill in]_ |
|
||||
| Photography / illustration | _[fill in]_ |
|
||||
| CMS / hosting / SaaS (annual) | _[fill in]_ |
|
||||
| Contingency (10–15%) | _[fill in]_ |
|
||||
| **Total** | _[fill in]_ |
|
||||
|
||||
---
|
||||
|
||||
## 19. Post-Launch: Maintenance & Growth
|
||||
|
||||
### 19.1 Ownership after launch
|
||||
- **Day-to-day content edits:** _[name / role]_
|
||||
- **Bug fixes & dev support:** _[fill in]_
|
||||
- **Hosting & DNS:** _[fill in]_
|
||||
|
||||
### 19.2 Ongoing work
|
||||
- [ ] Monthly performance / analytics review
|
||||
- [ ] Quarterly content refresh
|
||||
- [ ] Annual design review
|
||||
- [ ] SEO / content marketing retainer
|
||||
- [ ] Paid acquisition (landing pages)
|
||||
|
||||
### 19.3 Roadmap (post-launch features)
|
||||
Things we know we want but aren't launching with:
|
||||
1. _[fill in]_
|
||||
2. _[fill in]_
|
||||
3. _[fill in]_
|
||||
|
||||
---
|
||||
|
||||
## 20. Stakeholders & Approvals
|
||||
|
||||
| Name | Role | Email | Sign-off needed on |
|
||||
|---|---|---|---|
|
||||
| _[fill in]_ | Project sponsor | _[fill in]_ | Final launch |
|
||||
| _[fill in]_ | Marketing lead | _[fill in]_ | Copy, design |
|
||||
| _[fill in]_ | Tech lead | _[fill in]_ | Stack, integrations |
|
||||
| _[fill in]_ | Legal / compliance | _[fill in]_ | Privacy, ToS |
|
||||
| _[fill in]_ | Design lead | _[fill in]_ | Visual direction |
|
||||
|
||||
---
|
||||
|
||||
## 21. Open Questions & Risks
|
||||
|
||||
Track anything unresolved here so it doesn't get lost.
|
||||
|
||||
- [ ] _[Question or risk]_ — owner: _[name]_ — due: _[date]_
|
||||
- [ ] _[fill in]_
|
||||
- [ ] _[fill in]_
|
||||
|
||||
---
|
||||
|
||||
## 22. Appendix: Asset Checklist
|
||||
|
||||
Before development starts, gather these:
|
||||
- [ ] Logo (SVG + PNG, light + dark variants)
|
||||
- [ ] Brand guidelines (if any)
|
||||
- [ ] High-res photography (team, office, product)
|
||||
- [ ] Client logos (for social proof bar) — with permission to use
|
||||
- [ ] Testimonial quotes — with permission and attribution
|
||||
- [ ] Case study source material
|
||||
- [ ] Existing copy worth keeping
|
||||
- [ ] Press logos / awards / certifications
|
||||
- [ ] Video / motion assets
|
||||
- [ ] Founder / team bios + headshots
|
||||
- [ ] Social media handles & links
|
||||
- [ ] Office address, phone, support email
|
||||
|
||||
---
|
||||
|
||||
_End of document. Once every section above is filled in, this is everything needed to design, build, and launch the website._
|
||||
669
filled_design_document.md
Normal file
669
filled_design_document.md
Normal file
@@ -0,0 +1,669 @@
|
||||
# Website Design Document
|
||||
|
||||
> **How to use this document:** Fill in every section below. Replace the `_[fill in]_` placeholders with your details and tick the checkboxes that apply. Anywhere you see **💡 Recommendation**, that's a suggested default — keep it, edit it, or replace it. The more detail you provide, the closer the final website will match your vision.
|
||||
|
||||
---
|
||||
|
||||
## 1. Project Snapshot
|
||||
|
||||
| Field | Your Answer |
|
||||
|--------------------------------------|-----------------------------------------|
|
||||
| **Company name** | RisingCompute |
|
||||
| **Legal entity name (if different)** | RisingCompute Pvt Ltd |
|
||||
| **Primary domain** | risingcompute.in |
|
||||
| **Working title for the project** | RisingCompute Website Design |
|
||||
| **Target launch date** | 15-05-2026 |
|
||||
| **Budget range** | I am making |
|
||||
| **Document owner** | abhishek verma contact@risingcompute.in |
|
||||
| **Last updated** | 19-05-2026 |
|
||||
|
||||
---
|
||||
|
||||
## 2. Company Overview
|
||||
|
||||
### 2.1 Who we are
|
||||
- [ ] **What we do (one sentence):** bettering computing uisng acceleration on hardware layer
|
||||
- **Tagline / one-liner:** Accelerating the compute
|
||||
- **Elevator pitch (3–4 sentences):** we are building parallel computer architecture which can accelerate AI workflow on hardware level. building tech for AI, Space and Robotics. products are IP cores for cybersecurity and AI In future will develop chips also for specific AI application/
|
||||
|
||||
### 2.2 Mission, vision, values
|
||||
- **Mission:** To Accelerate compute in AI, Space and Robotics
|
||||
- **Vision:** Make computing better for future.
|
||||
- **Core values:** Fast, Reliable and Robust
|
||||
|
||||
### 2.3 Company facts
|
||||
- **Founded:** 2026
|
||||
- **Headquarters:** Surat, Gujarat
|
||||
- **Other offices / coverage areas:** STIIC at IIST(Indian Institue of space science and technology)
|
||||
- **Team size:** 5
|
||||
- **Industry / sector:** semiconductor and AI
|
||||
- **Stage:** _[ * ] Pre-revenue [ ] Early revenue [ ] Growth [ ] Established_
|
||||
|
||||
### 2.4 Our story
|
||||
_Brief origin story — why the company was started, key milestones, what makes the journey notable. 100–250 words._
|
||||
|
||||
> Our company started in 2026 with the vision to make computing better. We originated from a satellite development. lab as a team of computation development in SSPACE IIST. We realised that what privilege we are having as researchers to use AI we can also provide it to general people by making the computation architecture scalable and easy to expand.
|
||||
|
||||
### 2.5 Key milestones / achievements
|
||||
- Working for satellite software in research lab from last 2 years
|
||||
- Developed many IP cores which flown in SPACE
|
||||
- Developed independent IP cores for cybersecurty, AI inference and Communication protocols and currently in testing phase
|
||||
|
||||
---
|
||||
|
||||
## 3. Target Audience
|
||||
|
||||
### 3.1 Primary audience
|
||||
- **Who they are:** _[e.g. operations managers at 50–500-person SaaS companies]_
|
||||
- **Where they're based:** _[fill in]_
|
||||
- **Age range:** _[fill in]_
|
||||
- **Job titles / roles:** _[fill in]_
|
||||
- **Industries:** _[fill in]_
|
||||
|
||||
### 3.2 Audience personas
|
||||
Define 1–3 personas. Duplicate the block as needed.
|
||||
|
||||
**Persona 1 — _[name, e.g. "Ops Olivia"]_**
|
||||
- Role / background: _[fill in]_
|
||||
- Goals: _[What they want to achieve]_
|
||||
- Pain points: _[What frustrates them today]_
|
||||
- What they need from our site: _[e.g. proof we can scale, pricing clarity, a demo]_
|
||||
- Triggers to convert: _[fill in]_
|
||||
|
||||
**Persona 2 — _[name]_**
|
||||
- _[same fields]_
|
||||
|
||||
### 3.3 What we want visitors to do
|
||||
Rank in priority order (1 = most important):
|
||||
- [ ] Request a demo / consultation
|
||||
- [ ] Buy a product or service
|
||||
- [ ] Sign up for a free trial or newsletter
|
||||
- [ ] Download a resource (whitepaper, case study)
|
||||
- [ ] Contact sales
|
||||
- [ ] Apply for a job
|
||||
- [ ] Learn / build brand awareness
|
||||
- [ ] Other: _[fill in]_
|
||||
|
||||
---
|
||||
|
||||
## 4. Goals, KPIs & Success Metrics
|
||||
|
||||
### 4.1 Business goals for this website
|
||||
1. _[e.g. Generate 50 qualified leads per month]_
|
||||
2. _[fill in]_
|
||||
3. _[fill in]_
|
||||
|
||||
### 4.2 Measurable KPIs
|
||||
| KPI | Current baseline | 6-month target |
|
||||
|---|---|---|
|
||||
| Monthly unique visitors | _[fill in]_ | _[fill in]_ |
|
||||
| Conversion rate (visit → lead) | _[fill in]_ | _[fill in]_ |
|
||||
| Average session duration | _[fill in]_ | _[fill in]_ |
|
||||
| Demo / contact form submissions / month | _[fill in]_ | _[fill in]_ |
|
||||
| Organic search traffic | _[fill in]_ | _[fill in]_ |
|
||||
|
||||
### 4.3 What "success" looks like 12 months after launch
|
||||
> _[fill in]_
|
||||
|
||||
---
|
||||
|
||||
## 5. Competitor & Inspiration Landscape
|
||||
|
||||
### 5.1 Direct competitors
|
||||
| Competitor | URL | What they do well | Where they fall short |
|
||||
|---|---|---|---|
|
||||
| _[Name]_ | _[URL]_ | _[fill in]_ | _[fill in]_ |
|
||||
| _[Name]_ | _[URL]_ | _[fill in]_ | _[fill in]_ |
|
||||
| _[Name]_ | _[URL]_ | _[fill in]_ | _[fill in]_ |
|
||||
|
||||
### 5.2 Sites we love (any industry)
|
||||
List 3–5 sites whose design, copy, or feel you admire. Note **why**.
|
||||
- _[URL]_ — _[what you like: typography, color, motion, copywriting tone, layout, etc.]_
|
||||
- _[URL]_ — _[why]_
|
||||
- _[URL]_ — _[why]_
|
||||
|
||||
### 5.3 Sites we want to look nothing like
|
||||
- _[URL]_ — _[why not]_
|
||||
|
||||
### 5.4 Our differentiators
|
||||
What makes us genuinely different / better? Be specific.
|
||||
1. _[fill in]_
|
||||
2. _[fill in]_
|
||||
3. _[fill in]_
|
||||
|
||||
---
|
||||
|
||||
## 6. Products & Services
|
||||
|
||||
For each offering, fill in the block. Duplicate as needed.
|
||||
|
||||
### Offering 1 — _[name]_
|
||||
- **What it is:** _[fill in]_
|
||||
- **Who it's for:** _[fill in]_
|
||||
- **Key benefits (3–5):** _[fill in]_
|
||||
- **Features / what's included:** _[fill in]_
|
||||
- **Pricing model:** _[ ] Fixed [ ] Tiered [ ] Custom quote [ ] Hidden until contact_
|
||||
- **Price points (if shown):** _[fill in]_
|
||||
- **Primary CTA:** _[e.g. "Book a demo", "Get a quote"]_
|
||||
- **Supporting proof:** _[case studies, stats, testimonials to attach]_
|
||||
|
||||
### Offering 2 — _[name]_
|
||||
_[same fields]_
|
||||
|
||||
---
|
||||
|
||||
## 7. Brand Identity
|
||||
|
||||
### 7.1 Logo
|
||||
- [ ] We have a finalized logo (attach: _[file path / link]_)
|
||||
- [ ] We have a logo but it needs cleanup
|
||||
- [ ] We need a logo designed
|
||||
|
||||
### 7.2 Color palette
|
||||
List hex codes. If you don't have a palette yet, describe the mood and we'll propose one.
|
||||
|
||||
| Role | Color | Hex | Notes |
|
||||
|---|---|---|---|
|
||||
| Primary | _[e.g. Deep blue]_ | `#______` | Used for CTAs, links |
|
||||
| Secondary | _[fill in]_ | `#______` | _[fill in]_ |
|
||||
| Accent | _[fill in]_ | `#______` | Used sparingly for emphasis |
|
||||
| Neutral dark | _[fill in]_ | `#______` | Body text |
|
||||
| Neutral light | _[fill in]_ | `#______` | Backgrounds |
|
||||
| Success / Warning / Error | _[fill in]_ | `#______` | UI states |
|
||||
|
||||
> **💡 Recommendation:** Pick one primary brand color, one accent, and a neutral scale (5–7 grays). Avoid more than 3 saturated colors — it gets noisy fast.
|
||||
|
||||
### 7.3 Typography
|
||||
- **Heading font:** _[e.g. Inter / Custom / "open to suggestion"]_
|
||||
- **Body font:** _[fill in]_
|
||||
- **Monospace (if used):** _[fill in]_
|
||||
|
||||
> **💡 Recommendation:** Use a pairing like **Inter** (headings + body) or **Fraunces + Inter** (editorial feel + clean body). Both are free, web-optimized, and load fast.
|
||||
|
||||
### 7.4 Imagery & illustration style
|
||||
- [ ] Photography — real, candid people in our offices
|
||||
- [ ] Photography — stock (specify style: _[bright & airy / moody / corporate / lifestyle]_)
|
||||
- [ ] Custom illustration (style: _[fill in]_)
|
||||
- [ ] 3D renders
|
||||
- [ ] Icon-led, minimal imagery
|
||||
- [ ] Mix — describe: _[fill in]_
|
||||
|
||||
### 7.5 Voice & tone
|
||||
Pick 3–5 adjectives that describe how we sound:
|
||||
- [ ] Authoritative [ ] Friendly [ ] Playful [ ] Technical [ ] Aspirational
|
||||
- [ ] Witty [ ] Calm [ ] Direct [ ] Warm [ ] Bold
|
||||
- Other: _[fill in]_
|
||||
|
||||
**Example phrases we'd say:**
|
||||
> _[2–3 sample sentences in our voice]_
|
||||
|
||||
**Example phrases we'd never say:**
|
||||
> _[fill in]_
|
||||
|
||||
### 7.6 Existing brand assets
|
||||
- [ ] Brand guidelines doc — link: _[fill in]_
|
||||
- [ ] Logo files (SVG / PNG)
|
||||
- [ ] Photography library
|
||||
- [ ] Existing website copy worth keeping
|
||||
|
||||
---
|
||||
|
||||
## 8. Site Structure (Information Architecture)
|
||||
|
||||
### 8.1 Sitemap
|
||||
Tick the pages you want. Add custom ones at the bottom.
|
||||
|
||||
- [ ] **Home**
|
||||
- [ ] **About** — story, team, values
|
||||
- [ ] Team / Leadership sub-page
|
||||
- [ ] Careers sub-page
|
||||
- [ ] **Services** / **Products** — overview
|
||||
- [ ] Individual service / product pages (one per offering)
|
||||
- [ ] **Case Studies** / **Work** / **Portfolio**
|
||||
- [ ] Individual case study pages
|
||||
- [ ] **Pricing**
|
||||
- [ ] **Blog** / **Resources** / **Insights**
|
||||
- [ ] Article template
|
||||
- [ ] Category pages
|
||||
- [ ] **FAQ**
|
||||
- [ ] **Contact**
|
||||
- [ ] **Book a demo** / **Get a quote** (landing page)
|
||||
- [ ] **Press / News**
|
||||
- [ ] **Partners**
|
||||
- [ ] **404 page**
|
||||
- [ ] **Thank-you pages** (post-form)
|
||||
- [ ] **Privacy Policy** _(required)_
|
||||
- [ ] **Terms of Service** _(required)_
|
||||
- [ ] **Cookie Policy** _(if EU/UK visitors)_
|
||||
- Custom: _[fill in]_
|
||||
|
||||
### 8.2 Primary navigation
|
||||
List the top-nav items in order:
|
||||
1. _[fill in]_
|
||||
2. _[fill in]_
|
||||
3. _[fill in]_
|
||||
4. _[fill in]_
|
||||
5. **CTA button** — label: _[e.g. "Book a demo"]_
|
||||
|
||||
### 8.3 Footer
|
||||
- [ ] Mini sitemap
|
||||
- [ ] Contact info (address, phone, email)
|
||||
- [ ] Social links: _[which platforms]_
|
||||
- [ ] Newsletter signup
|
||||
- [ ] Legal links (Privacy, Terms, Cookies)
|
||||
- [ ] Company registration number / VAT (if required)
|
||||
- [ ] Industry certifications / logos
|
||||
|
||||
---
|
||||
|
||||
## 9. Page-by-Page Content Brief
|
||||
|
||||
### 9.1 Home
|
||||
- **Hero headline (max 10 words):** _[fill in]_
|
||||
- **Hero sub-headline (1–2 sentences):** _[fill in]_
|
||||
- **Primary CTA:** _[label + destination]_
|
||||
- **Secondary CTA:** _[label + destination]_
|
||||
- **Sections to include (in order):**
|
||||
- [ ] Hero with visual
|
||||
- [ ] Social proof bar (client logos / press)
|
||||
- [ ] What we do (3–4 service highlights)
|
||||
- [ ] How it works / process
|
||||
- [ ] Why us / differentiators
|
||||
- [ ] Featured case study or proof point
|
||||
- [ ] Testimonials
|
||||
- [ ] Stats / metrics
|
||||
- [ ] Recent blog posts
|
||||
- [ ] Final CTA block
|
||||
- **Key visuals needed:** _[fill in]_
|
||||
|
||||
### 9.2 About
|
||||
- Origin story: _[link to §2.4 or expand here]_
|
||||
- Team intro: _[ ] full team grid [ ] leadership only [ ] no photos_
|
||||
- Values block: _[link to §2.2]_
|
||||
- Office / culture photos: _[ ] yes [ ] no_
|
||||
- Press / awards row: _[ ] yes [ ] no_
|
||||
|
||||
### 9.3 Services / Products
|
||||
For each offering, one page with:
|
||||
- Hero with the offering name + one-liner
|
||||
- The problem it solves
|
||||
- How it works (steps or features)
|
||||
- What's included
|
||||
- Pricing or "request a quote"
|
||||
- FAQs specific to this offering
|
||||
- CTA
|
||||
|
||||
### 9.4 Case Studies / Work
|
||||
- Number of case studies at launch: _[fill in]_
|
||||
- Template per case study:
|
||||
- Client + industry
|
||||
- Challenge (the problem)
|
||||
- Approach (what we did)
|
||||
- Outcome (metrics, quotes)
|
||||
- Visuals: _[before/after, screenshots, photos]_
|
||||
|
||||
### 9.5 Pricing _(if applicable)_
|
||||
- [ ] Show full pricing
|
||||
- [ ] Show tiers, hide exact numbers
|
||||
- [ ] "Contact us" only
|
||||
- Tiers: _[list each tier with price + what's included]_
|
||||
- Add-ons: _[fill in]_
|
||||
|
||||
### 9.6 Blog / Resources
|
||||
- Launch with how many posts? _[fill in]_
|
||||
- Categories: _[fill in]_
|
||||
- Authors shown? _[ ] yes [ ] no_
|
||||
- Comments enabled? _[ ] yes [ ] no_
|
||||
- Newsletter signup on every post? _[ ] yes [ ] no_
|
||||
|
||||
### 9.7 Contact
|
||||
- [ ] Contact form (fields: _[name, email, company, message, ...]_)
|
||||
- [ ] Direct email
|
||||
- [ ] Phone number
|
||||
- [ ] Physical address + map
|
||||
- [ ] Office hours
|
||||
- [ ] Calendly / booking link
|
||||
- [ ] Live chat widget
|
||||
|
||||
### 9.8 Other pages
|
||||
_[Add custom briefs as needed]_
|
||||
|
||||
---
|
||||
|
||||
## 10. Features & Functionality
|
||||
|
||||
Tick everything the site needs:
|
||||
|
||||
**Lead capture & forms**
|
||||
- [ ] Contact form
|
||||
- [ ] Demo request form
|
||||
- [ ] Quote / estimate form
|
||||
- [ ] Newsletter signup
|
||||
- [ ] Gated content (downloads behind email)
|
||||
- [ ] Multi-step / progressive forms
|
||||
|
||||
**Content & engagement**
|
||||
- [ ] Blog with categories & tags
|
||||
- [ ] Search
|
||||
- [ ] Filtering on listings (case studies, blog)
|
||||
- [ ] Comments
|
||||
- [ ] Social share buttons
|
||||
- [ ] RSS feed
|
||||
|
||||
**Booking & scheduling**
|
||||
- [ ] Calendly / Cal.com embed
|
||||
- [ ] Custom booking flow
|
||||
- [ ] Event RSVPs
|
||||
|
||||
**Commerce / payments**
|
||||
- [ ] One-off product checkout
|
||||
- [ ] Subscription billing (Stripe)
|
||||
- [ ] Invoice / quote generation
|
||||
|
||||
**Authentication / portal**
|
||||
- [ ] Client login area
|
||||
- [ ] Account dashboard
|
||||
- [ ] File / document sharing
|
||||
|
||||
**Interactivity**
|
||||
- [ ] Animations / scroll effects
|
||||
- [ ] Video backgrounds
|
||||
- [ ] Interactive product tour
|
||||
- [ ] Calculator / configurator
|
||||
- [ ] Live chat (Intercom / Crisp / HubSpot)
|
||||
- [ ] Chatbot (AI / rules-based)
|
||||
|
||||
**Localization**
|
||||
- [ ] Multi-language: _[which languages]_
|
||||
- [ ] Multi-currency
|
||||
- [ ] Region-aware content
|
||||
|
||||
**Other:** _[fill in]_
|
||||
|
||||
---
|
||||
|
||||
## 11. Design Direction
|
||||
|
||||
### 11.1 Mood
|
||||
Pick the words that fit. Strike through ones that don't.
|
||||
Minimalist · Bold · Elegant · Playful · Editorial · Corporate · Warm · Futuristic · Premium · Approachable · Technical · Human · Spacious · Dense · Quiet · Energetic
|
||||
|
||||
**Top 3 for our brand:** _[fill in]_
|
||||
|
||||
### 11.2 Layout preferences
|
||||
- **Density:** _[ ] Spacious / lots of whitespace [ ] Balanced [ ] Dense / information-rich_
|
||||
- **Width:** _[ ] Full-bleed / edge-to-edge [ ] Contained (max ~1200–1400px)_
|
||||
- **Page rhythm:** _[ ] One idea per scroll-section [ ] Multi-column / magazine-style_
|
||||
|
||||
### 11.3 Motion & interactivity
|
||||
- [ ] No motion — fast and static
|
||||
- [ ] Subtle (fade-ins, hover states)
|
||||
- [ ] Moderate (scroll-triggered reveals, parallax)
|
||||
- [ ] Rich (custom animations, WebGL, video)
|
||||
|
||||
### 11.4 Devices to prioritize
|
||||
- [ ] Mobile-first (most traffic on phones)
|
||||
- [ ] Desktop-first (B2B sales context)
|
||||
- [ ] Equal weight
|
||||
- **Browser support:** _[modern evergreen / IE11 / specify]_
|
||||
|
||||
---
|
||||
|
||||
## 12. Tech Stack
|
||||
|
||||
### 12.1 Frontend framework
|
||||
- [ ] **Next.js (React)** — 💡 Recommended for marketing sites that need flexibility, blog, and excellent SEO
|
||||
- [ ] **Astro** — 💡 Recommended for content-heavy, mostly-static sites; fastest performance
|
||||
- [ ] **SvelteKit** — modern, lean, great DX
|
||||
- [ ] **Plain HTML/CSS/JS** — simplest, for very small sites
|
||||
- [ ] Other: _[fill in]_
|
||||
|
||||
### 12.2 Styling
|
||||
- [ ] **Tailwind CSS** — 💡 Recommended, fastest to iterate
|
||||
- [ ] CSS Modules
|
||||
- [ ] Styled Components / Emotion
|
||||
- [ ] Vanilla CSS
|
||||
- [ ] Other: _[fill in]_
|
||||
|
||||
### 12.3 CMS / Content management
|
||||
Where will marketing edit content?
|
||||
- [ ] **Sanity** — 💡 Recommended; flexible schemas, great editor UX
|
||||
- [ ] **Contentful** — enterprise-friendly, more expensive
|
||||
- [ ] **Strapi** — self-hosted, open source
|
||||
- [ ] **WordPress (headless)** — familiar editor, huge ecosystem
|
||||
- [ ] **Markdown in the repo** — for tech-savvy teams, no CMS overhead
|
||||
- [ ] **Notion as CMS** — easy for non-technical teams
|
||||
- [ ] No CMS — developers update content directly
|
||||
- [ ] Other: _[fill in]_
|
||||
|
||||
### 12.4 Hosting & deployment
|
||||
- [ ] **Vercel** — 💡 Recommended for Next.js; preview URLs, zero config
|
||||
- [ ] **Netlify** — great for Astro / static sites
|
||||
- [ ] **Cloudflare Pages** — fast, generous free tier
|
||||
- [ ] AWS / GCP / Azure — if existing cloud commitments
|
||||
- [ ] Other: _[fill in]_
|
||||
|
||||
### 12.5 Domain & DNS
|
||||
- **Existing domain:** _[fill in]_
|
||||
- **Registrar:** _[fill in]_
|
||||
- **DNS provider:** _[ ] Same as registrar [ ] Cloudflare [ ] Other_
|
||||
- **Email hosting:** _[Google Workspace / Microsoft 365 / other]_
|
||||
|
||||
### 12.6 Forms backend
|
||||
- [ ] **HubSpot Forms** — if using HubSpot CRM
|
||||
- [ ] **Formspree / Basin** — simple email-based handling
|
||||
- [ ] **Custom API + database**
|
||||
- [ ] CMS-native (Sanity, etc.)
|
||||
|
||||
### 12.7 Repository & CI
|
||||
- **Code host:** _[ ] GitHub [ ] GitLab [ ] Bitbucket_
|
||||
- **CI/CD:** _[ ] Vercel/Netlify built-in [ ] GitHub Actions [ ] Other_
|
||||
|
||||
---
|
||||
|
||||
## 13. Integrations
|
||||
|
||||
Tick everything that needs to talk to the website.
|
||||
|
||||
**Analytics & attribution**
|
||||
- [ ] Google Analytics 4
|
||||
- [ ] Plausible / Fathom (privacy-friendly) — 💡 Recommended if GDPR matters
|
||||
- [ ] PostHog (product analytics)
|
||||
- [ ] Hotjar / Microsoft Clarity (heatmaps & recordings)
|
||||
|
||||
**Marketing & CRM**
|
||||
- [ ] HubSpot
|
||||
- [ ] Salesforce
|
||||
- [ ] Pipedrive
|
||||
- [ ] Mailchimp / ConvertKit / Beehiiv (newsletter)
|
||||
- [ ] Customer.io / Klaviyo
|
||||
|
||||
**Communication**
|
||||
- [ ] Slack notifications on form submits
|
||||
- [ ] Intercom / Crisp / HelpScout (live chat / helpdesk)
|
||||
|
||||
**Booking & payments**
|
||||
- [ ] Calendly / Cal.com
|
||||
- [ ] Stripe
|
||||
- [ ] PayPal
|
||||
|
||||
**Other**
|
||||
- [ ] Algolia / Meilisearch (search)
|
||||
- [ ] Tag manager (GTM)
|
||||
- [ ] reCAPTCHA / Turnstile (form spam)
|
||||
- Custom API: _[fill in]_
|
||||
|
||||
---
|
||||
|
||||
## 14. SEO & Content Strategy
|
||||
|
||||
### 14.1 Target keywords
|
||||
List 5–15 keywords / phrases you want to rank for.
|
||||
1. _[fill in]_
|
||||
2. _[fill in]_
|
||||
3. _[fill in]_
|
||||
|
||||
### 14.2 Per-page meta
|
||||
We'll fill these per page during build, but flag any **must-have** titles or descriptions here.
|
||||
- _[fill in]_
|
||||
|
||||
### 14.3 Structured data
|
||||
- [ ] Organization schema
|
||||
- [ ] LocalBusiness schema (if relevant)
|
||||
- [ ] Article schema (blog)
|
||||
- [ ] FAQ schema
|
||||
- [ ] Product / Service schema
|
||||
- [ ] BreadcrumbList
|
||||
|
||||
### 14.4 Redirects / migration
|
||||
If replacing an existing site:
|
||||
- [ ] Old sitemap to preserve: _[link]_
|
||||
- [ ] 301 redirect map needed: _[ ] yes [ ] no_
|
||||
- [ ] URL structure changing? _[fill in]_
|
||||
|
||||
### 14.5 Content production
|
||||
- Who writes the copy? _[ ] We will [ ] You / your team [ ] External copywriter_
|
||||
- Who edits the blog post-launch? _[fill in]_
|
||||
- Cadence: _[posts per month]_
|
||||
|
||||
---
|
||||
|
||||
## 15. Accessibility, Compliance & Legal
|
||||
|
||||
### 15.1 Accessibility
|
||||
- [ ] WCAG 2.1 **AA** target — 💡 Recommended baseline
|
||||
- [ ] WCAG 2.1 AAA (stricter, for public-sector / health)
|
||||
- [ ] No specific target
|
||||
|
||||
### 15.2 Privacy & data
|
||||
- **Visitors from EU/UK?** _[ ] yes [ ] no_ → if yes, GDPR applies
|
||||
- **Visitors from California?** _[ ] yes [ ] no_ → if yes, CCPA applies
|
||||
- [ ] Cookie consent banner needed
|
||||
- [ ] Privacy policy already exists — link: _[fill in]_
|
||||
- [ ] Need privacy policy written
|
||||
- [ ] Terms of service already exists — link: _[fill in]_
|
||||
- [ ] Need ToS written
|
||||
- **Data controller / DPO contact:** _[fill in]_
|
||||
|
||||
### 15.3 Industry-specific
|
||||
- [ ] Healthcare (HIPAA) — _[fill in]_
|
||||
- [ ] Finance / banking — _[fill in]_
|
||||
- [ ] Children's products (COPPA)
|
||||
- [ ] Other regulated: _[fill in]_
|
||||
|
||||
---
|
||||
|
||||
## 16. Performance & Quality Bar
|
||||
|
||||
### 16.1 Performance targets
|
||||
- [ ] **Lighthouse score 90+** on mobile (performance, accessibility, SEO) — 💡 Recommended
|
||||
- [ ] **LCP < 2.5s**, **CLS < 0.1**, **INP < 200ms** (Core Web Vitals "good")
|
||||
- [ ] Page weight under _[e.g. 1 MB]_ on landing pages
|
||||
|
||||
### 16.2 Browser support
|
||||
- Modern Chrome / Safari / Firefox / Edge (last 2 versions) — 💡 Recommended default
|
||||
- [ ] Need IE11 / older support: _[describe]_
|
||||
|
||||
### 16.3 Quality assurance
|
||||
- [ ] Cross-browser testing
|
||||
- [ ] Mobile device testing (iOS Safari, Android Chrome)
|
||||
- [ ] Accessibility audit (manual + automated)
|
||||
- [ ] Performance audit (Lighthouse + WebPageTest)
|
||||
- [ ] SEO audit pre-launch
|
||||
|
||||
---
|
||||
|
||||
## 17. Timeline & Milestones
|
||||
|
||||
| Milestone | Target date | Owner |
|
||||
|---|---|---|
|
||||
| Design document signed off | _[date]_ | _[name]_ |
|
||||
| Wireframes approved | _[date]_ | _[name]_ |
|
||||
| Visual designs approved | _[date]_ | _[name]_ |
|
||||
| Content delivered | _[date]_ | _[name]_ |
|
||||
| Development complete | _[date]_ | _[name]_ |
|
||||
| QA / UAT | _[date]_ | _[name]_ |
|
||||
| Soft launch / staging review | _[date]_ | _[name]_ |
|
||||
| **Public launch** | _[date]_ | _[name]_ |
|
||||
|
||||
---
|
||||
|
||||
## 18. Budget
|
||||
|
||||
| Bucket | Estimate |
|
||||
|---|---|
|
||||
| Design | _[fill in]_ |
|
||||
| Development | _[fill in]_ |
|
||||
| Copywriting | _[fill in]_ |
|
||||
| Photography / illustration | _[fill in]_ |
|
||||
| CMS / hosting / SaaS (annual) | _[fill in]_ |
|
||||
| Contingency (10–15%) | _[fill in]_ |
|
||||
| **Total** | _[fill in]_ |
|
||||
|
||||
---
|
||||
|
||||
## 19. Post-Launch: Maintenance & Growth
|
||||
|
||||
### 19.1 Ownership after launch
|
||||
- **Day-to-day content edits:** _[name / role]_
|
||||
- **Bug fixes & dev support:** _[fill in]_
|
||||
- **Hosting & DNS:** _[fill in]_
|
||||
|
||||
### 19.2 Ongoing work
|
||||
- [ ] Monthly performance / analytics review
|
||||
- [ ] Quarterly content refresh
|
||||
- [ ] Annual design review
|
||||
- [ ] SEO / content marketing retainer
|
||||
- [ ] Paid acquisition (landing pages)
|
||||
|
||||
### 19.3 Roadmap (post-launch features)
|
||||
Things we know we want but aren't launching with:
|
||||
1. _[fill in]_
|
||||
2. _[fill in]_
|
||||
3. _[fill in]_
|
||||
|
||||
---
|
||||
|
||||
## 20. Stakeholders & Approvals
|
||||
|
||||
| Name | Role | Email | Sign-off needed on |
|
||||
|---|---|---|---|
|
||||
| _[fill in]_ | Project sponsor | _[fill in]_ | Final launch |
|
||||
| _[fill in]_ | Marketing lead | _[fill in]_ | Copy, design |
|
||||
| _[fill in]_ | Tech lead | _[fill in]_ | Stack, integrations |
|
||||
| _[fill in]_ | Legal / compliance | _[fill in]_ | Privacy, ToS |
|
||||
| _[fill in]_ | Design lead | _[fill in]_ | Visual direction |
|
||||
|
||||
---
|
||||
|
||||
## 21. Open Questions & Risks
|
||||
|
||||
Track anything unresolved here so it doesn't get lost.
|
||||
|
||||
- [ ] _[Question or risk]_ — owner: _[name]_ — due: _[date]_
|
||||
- [ ] _[fill in]_
|
||||
- [ ] _[fill in]_
|
||||
|
||||
---
|
||||
|
||||
## 22. Appendix: Asset Checklist
|
||||
|
||||
Before development starts, gather these:
|
||||
- [ ] Logo (SVG + PNG, light + dark variants)
|
||||
- [ ] Brand guidelines (if any)
|
||||
- [ ] High-res photography (team, office, product)
|
||||
- [ ] Client logos (for social proof bar) — with permission to use
|
||||
- [ ] Testimonial quotes — with permission and attribution
|
||||
- [ ] Case study source material
|
||||
- [ ] Existing copy worth keeping
|
||||
- [ ] Press logos / awards / certifications
|
||||
- [ ] Video / motion assets
|
||||
- [ ] Founder / team bios + headshots
|
||||
- [ ] Social media handles & links
|
||||
- [ ] Office address, phone, support email
|
||||
|
||||
---
|
||||
|
||||
_End of document. Once every section above is filled in, this is everything needed to design, build, and launch the website._
|
||||
|
||||
#folder
|
||||
703
final_design_document.md
Normal file
703
final_design_document.md
Normal file
@@ -0,0 +1,703 @@
|
||||
# RisingCompute — Website Design Document (Final)
|
||||
|
||||
> **Status:** Complete. This is the build-ready spec for the RisingCompute marketing website. Every section has been finalised from the company brief; revisions tracked in §0.
|
||||
|
||||
---
|
||||
|
||||
## 0. Revision History
|
||||
|
||||
| Version | Date | Author | Notes |
|
||||
|---|---|---|---|
|
||||
| 0.1 | 18 May 2026 | Abhishek Verma | Initial fill-in of company sections |
|
||||
| 1.0 | 19 May 2026 | Abhishek Verma | Final document — all sections completed, target launch revised |
|
||||
| 1.1 | 19 May 2026 | Abhishek Verma | Added founders section (§2.6); updated About page brief (§9.2) and stakeholder table (§20) |
|
||||
|
||||
---
|
||||
|
||||
## 1. Project Snapshot
|
||||
|
||||
| Field | Answer |
|
||||
|---|---|
|
||||
| **Company name** | RisingCompute |
|
||||
| **Legal entity name** | RisingCompute Pvt Ltd |
|
||||
| **Primary domain** | risingcompute.in |
|
||||
| **Working title for the project** | RisingCompute Website Design |
|
||||
| **Target launch date** | 30 June 2026 (revised from 15 May 2026) |
|
||||
| **Budget range** | Bootstrapped / built in-house — out-of-pocket cost target under ₹20,000 (domain, photography, third-party SaaS) |
|
||||
| **Document owner** | Abhishek Verma — contact@risingcompute.in |
|
||||
| **Last updated** | 19 May 2026 |
|
||||
|
||||
---
|
||||
|
||||
## 2. Company Overview
|
||||
|
||||
### 2.1 Who we are
|
||||
- **What we do (one sentence):** RisingCompute designs parallel computer architectures and IP cores that accelerate AI, space, and robotics workloads at the hardware layer.
|
||||
- **Tagline / one-liner:** Accelerating the compute.
|
||||
- **Elevator pitch:** RisingCompute is a deep-tech semiconductor company building parallel computer architectures that accelerate AI workflows at the hardware level. Our IP cores power applications in AI, space, and robotics — including cybersecurity acceleration, AI inference, and space-qualified communication protocols. Born out of two years of satellite computation research at IIST, we are taking the same compute privilege researchers enjoy and packaging it into scalable, reusable hardware blocks. The long-term roadmap is custom AI ASICs for specific application classes.
|
||||
|
||||
### 2.2 Mission, vision, values
|
||||
- **Mission:** Accelerate compute for AI, space, and robotics.
|
||||
- **Vision:** Make computing better for the future — affordable, scalable, and accessible.
|
||||
- **Core values:** Fast · Reliable · Robust.
|
||||
|
||||
### 2.3 Company facts
|
||||
- **Founded:** 2026
|
||||
- **Headquarters:** Surat, Gujarat, India
|
||||
- **Other offices / coverage areas:** STIIC (Space Technology Incubation & Innovation Cell), IIST — Indian Institute of Space Science and Technology, Thiruvananthapuram
|
||||
- **Team size:** 5
|
||||
- **Industry / sector:** Semiconductors · AI hardware
|
||||
- **Stage:** **[x] Pre-revenue** [ ] Early revenue [ ] Growth [ ] Established
|
||||
|
||||
### 2.4 Our story
|
||||
> RisingCompute began in 2026 inside the SSPACE lab at IIST, where our founding team spent two years building computation systems for satellites — IP that has since flown in space. Working at that level taught us something simple: the difference between what a research team can do with AI and what most engineers and companies can do comes down to the compute they have access to. We started RisingCompute to close that gap. By building parallel hardware architectures and re-usable IP cores, we make accelerated compute scalable and easy to integrate — so an aerospace OEM, a robotics startup, or a defense electronics lab can get research-grade performance without rebuilding the stack from scratch.
|
||||
|
||||
### 2.5 Key milestones / achievements
|
||||
- 2 years of satellite-software research at SSPACE, IIST.
|
||||
- IP cores flown on operational satellite missions.
|
||||
- Independent IP cores for cybersecurity, AI inference, and communication protocols — currently in testing.
|
||||
- Incubated at STIIC, IIST.
|
||||
|
||||
### 2.6 Founders
|
||||
RisingCompute is founded by a three-person engineering team that has worked together inside the SSPACE lab at IIST. Each founder owns a clear technical domain, and together they cover the full stack from system architecture down to silicon.
|
||||
|
||||
| Founder | Role | Domain |
|
||||
|---|---|---|
|
||||
| **Ali Murabbi** | Co-founder · VLSI & Robotics Engineer | RTL / FPGA design, robotics control hardware, motion and sensor-fusion blocks. Leads the Communication Protocol IP and robotics-facing inference work. |
|
||||
| **Bhavy Savani** | Co-founder · VLSI & AI Engineer | RTL / FPGA design, quantised neural-network accelerators, verification. Leads the AI Inference IP Core and the Cybersecurity IP Core. |
|
||||
| **Abhishek Verma** | Co-founder · System Engineer & Project Manager | System architecture, integration, project delivery, GTM, and external relationships. Document owner; primary point of contact at contact@risingcompute.in. |
|
||||
|
||||
Short bios (used on the About page and press kit):
|
||||
|
||||
- **Ali Murabbi — Co-founder, VLSI & Robotics Engineer.** Hardware designer specialising in RTL and FPGA for robotics and motion systems. At SSPACE, IIST, contributed to onboard compute blocks for satellite payloads and now leads RisingCompute's communication-protocol and robotics IP work.
|
||||
- **Bhavy Savani — Co-founder, VLSI & AI Engineer.** VLSI engineer focused on AI accelerator architectures and verification. At SSPACE, IIST, designed and verified compute IP that has flown in space; at RisingCompute, leads the AI Inference IP Core and the Cybersecurity IP Core.
|
||||
- **Abhishek Verma — Co-founder, System Engineer & Project Manager.** Systems engineer and programme lead. Brings the IP, the engineering team, and the customer programme together — sets architecture, owns project delivery, and runs partner and customer conversations.
|
||||
|
||||
---
|
||||
|
||||
## 3. Target Audience
|
||||
|
||||
### 3.1 Primary audience
|
||||
- **Who they are:** VLSI / FPGA design engineers, system architects, and R&D heads at organisations building flight, defense, robotics, or AI-edge hardware. Plus procurement leads at primes who licence IP cores rather than build in-house.
|
||||
- **Where they're based:** Primary — India (Bengaluru, Hyderabad, Thiruvananthapuram, Ahmedabad, Pune). Expansion — APAC (Singapore, Japan), then US and EU.
|
||||
- **Age range:** 26–55
|
||||
- **Job titles / roles:** VLSI engineer, FPGA engineer, ASIC designer, system architect, CTO, head of R&D, hardware lead, payload engineer, principal investigator, head of procurement.
|
||||
- **Industries:** Aerospace, defense electronics, space systems, robotics, AI compute / edge AI, semiconductors, automotive, telecom.
|
||||
|
||||
### 3.2 Audience personas
|
||||
|
||||
**Persona 1 — "ASIC Arjun"**
|
||||
- Role / background: Senior VLSI engineer at a satellite-payload company. ~8 years experience. Verilog/SystemVerilog daily, comfortable with FPGAs, occasional ASIC tape-outs.
|
||||
- Goals: Hit payload power and latency targets without re-inventing protocol blocks; reduce design schedule risk.
|
||||
- Pain points: Western IP vendors are expensive, slow to support, and rarely qualified for space environments; reinventing in-house eats 6–12 months per project.
|
||||
- What they need from our site: Datasheets, performance numbers, FPGA/ASIC support details, flight heritage evidence, an obvious "request evaluation" path.
|
||||
- Triggers to convert: Verified flight heritage, downloadable datasheet, response within 24 hours to an evaluation request.
|
||||
|
||||
**Persona 2 — "Research Riya"**
|
||||
- Role / background: R&D head at a robotics or edge-AI startup, ~10 years experience, ex-academia. Pushes vision and control loops to the edge.
|
||||
- Goals: Run larger models on the same power budget; shorten inference latency.
|
||||
- Pain points: GPU power draw is impossible at the edge; existing NPU IP is opaque, locked, expensive.
|
||||
- What they need from our site: Clear architecture story, benchmarks vs. common baselines (Jetson, Coral, Hailo), licence model, partnership channel.
|
||||
- Triggers to convert: Credible benchmark numbers, a technical blog post that respects her intelligence, a 30-min architect call.
|
||||
|
||||
**Persona 3 — "Procurement Deepak"**
|
||||
- Role / background: Strategic procurement / programme manager at a defense electronics prime. Buys IP and outsources design.
|
||||
- Goals: De-risk supply chain by sourcing Indian-origin IP for defense / DRDO programmes; meet "Make in India" content rules.
|
||||
- Pain points: Few credible Indian semiconductor IP vendors; uncertainty around long-term support and security certification.
|
||||
- What they need from our site: Company legitimacy (incubation, founders, address), security and compliance posture, a formal contact path.
|
||||
- Triggers to convert: Credentialed founders, government incubation badge, a phone-able address and direct email.
|
||||
|
||||
### 3.3 What we want visitors to do
|
||||
Priority order:
|
||||
1. **[x] Contact sales / request evaluation** — start an IP licensing or pilot conversation.
|
||||
2. **[x] Download a resource** — datasheets, architecture whitepapers, benchmark briefs (lead-gated).
|
||||
3. **[x] Learn / build brand awareness** — read about the company, founders, IIST heritage.
|
||||
4. **[x] Sign up for the newsletter** — quarterly technical update.
|
||||
5. **[x] Apply for a job** — careers page open from launch.
|
||||
6. **[x] Request a demo / consultation** — 30-minute architect call.
|
||||
- [ ] Buy a product or service _(not applicable — long-cycle B2B sales, no online checkout)_
|
||||
|
||||
---
|
||||
|
||||
## 4. Goals, KPIs & Success Metrics
|
||||
|
||||
### 4.1 Business goals for this website
|
||||
1. Generate 15–20 qualified IP-licensing or evaluation enquiries per quarter by Q4 2026.
|
||||
2. Establish RisingCompute as the most credible India-origin semiconductor IP vendor for AI, space, and robotics.
|
||||
3. Support fundraising and grant applications with a public, professional presence (founder bios, traction, press, technical depth).
|
||||
4. Build an inbound talent funnel — receive 5+ relevant applications per open role per month.
|
||||
|
||||
### 4.2 Measurable KPIs
|
||||
|
||||
| KPI | Current baseline | 6-month target (Dec 2026) |
|
||||
|---|---|---|
|
||||
| Monthly unique visitors | 0 | 3,000 |
|
||||
| Conversion rate (visit → lead) | 0% | 2.0% |
|
||||
| Average session duration | 0 | 1 min 30 sec |
|
||||
| Demo / contact form submissions / month | 0 | 15–20 |
|
||||
| Datasheet downloads / month | 0 | 80 |
|
||||
| Organic search traffic / month | 0 | 1,000 |
|
||||
| Career applications / month | 0 | 10 |
|
||||
|
||||
### 4.3 What "success" looks like 12 months after launch
|
||||
> By May 2027, risingcompute.in is the default search result for "India IP core for AI / space / robotics." It has driven 80+ qualified inbound conversations, supported a pre-seed raise with credible founder and traction pages, on-boarded the first three paying pilot customers, and built a 500-subscriber technical newsletter.
|
||||
|
||||
---
|
||||
|
||||
## 5. Competitor & Inspiration Landscape
|
||||
|
||||
### 5.1 Direct competitors
|
||||
|
||||
| Competitor | URL | What they do well | Where they fall short |
|
||||
|---|---|---|---|
|
||||
| Arm | arm.com | Dominant IP brand, deep documentation, huge ecosystem | Generic — no flight heritage, expensive for startups, opaque licensing |
|
||||
| Synopsys DesignWare | synopsys.com | Breadth of IP, strong verification | Enterprise-only feel, no AI-specialist narrative |
|
||||
| SiFive | sifive.com | Clean modern brand, strong RISC-V narrative, developer-friendly | US-centric, AI-edge story is recent |
|
||||
| Hailo | hailo.ai | Sharp AI-accelerator positioning, benchmarks-forward | Focused on edge vision; closed architecture |
|
||||
| VeriSilicon | verisilicon.com | Broad IP catalogue and ASIC services | Site feels dated; hard to navigate |
|
||||
| Mythic / BrainChip | mythic.ai · brainchip.com | Differentiated architecture story | Narrow application focus |
|
||||
|
||||
### 5.2 Sites we love (and why)
|
||||
- **linear.app** — confident dark theme, restrained motion, exceptional typography, copy that respects the reader.
|
||||
- **stripe.com** — editorial layout, gradient mesh imagery, "products" architecture we should learn from.
|
||||
- **groq.com** — closest peer in tone: hardware-AI company, technical without being a wall of PDFs.
|
||||
- **sifive.com** — RISC-V IP peer with a developer-respecting site.
|
||||
- **vercel.com** — fast, minimal, technical-but-warm voice.
|
||||
|
||||
### 5.3 Sites we want to look nothing like
|
||||
- Generic semiconductor-incumbent sites that are 1000-link mega-menus, stock photos of handshakes, and PDFs from 2014.
|
||||
|
||||
### 5.4 Our differentiators
|
||||
1. **Space-flight heritage from day one** — our IP has flown; few startups can say this.
|
||||
2. **India-origin sovereign-stack IP** — meaningful for ISRO ecosystem, DRDO supply chains, and "Make in India" content rules.
|
||||
3. **One vendor across cybersecurity, AI inference, and communication IP** — adjacent blocks that are usually sourced from three different vendors.
|
||||
4. **Founder-led technical engagement** — every evaluation request lands with an engineer, not a sales rep.
|
||||
|
||||
---
|
||||
|
||||
## 6. Products & Services
|
||||
|
||||
### Offering 1 — AI Inference IP Core
|
||||
- **What it is:** A parallel-compute IP core for running quantised neural networks on FPGA / ASIC — targeted at vision, sensor fusion, and on-orbit inference.
|
||||
- **Who it's for:** Edge-AI product teams, robotics R&D, satellite payload engineers.
|
||||
- **Key benefits:**
|
||||
- Higher throughput per watt than CPU/GPU at the edge.
|
||||
- Deterministic latency — important for control loops and real-time payloads.
|
||||
- Quantisation-aware data path (INT8 / INT4) without accuracy collapse.
|
||||
- Synthesises on standard FPGA tooling.
|
||||
- Same RTL portable from FPGA prototype to ASIC tape-out.
|
||||
- **Features / what's included:** Parameterised RTL, testbench, reference compiler for ONNX subset, integration guide, FPGA reference design.
|
||||
- **Pricing model:** **[x] Custom quote** _(per-project licence)_
|
||||
- **Price points:** Disclosed under NDA after a qualification call.
|
||||
- **Primary CTA:** "Request evaluation"
|
||||
- **Supporting proof:** Flight-heritage record from satellite missions; benchmark brief vs. Jetson / Coral / Hailo.
|
||||
|
||||
### Offering 2 — Cybersecurity IP Core
|
||||
- **What it is:** Hardware accelerator for symmetric / asymmetric cryptography and secure boot — drop-in block for SoC designs.
|
||||
- **Who it's for:** Defense electronics, secure-element designers, comms equipment OEMs.
|
||||
- **Key benefits:** Constant-time implementation, side-channel hardened, FIPS-aligned, low gate count.
|
||||
- **Features / what's included:** RTL block, integration AXI/AHB wrappers, verification plan, test vectors, security white paper.
|
||||
- **Pricing model:** **[x] Custom quote**
|
||||
- **Price points:** Disclosed under NDA.
|
||||
- **Primary CTA:** "Request evaluation"
|
||||
- **Supporting proof:** Independent test reports, founder credentials.
|
||||
|
||||
### Offering 3 — Communication Protocol IP Cores
|
||||
- **What it is:** Space- and avionics-grade communication protocol IP — SpaceWire, CAN, UART/SPI/I2C, and custom satellite payload buses.
|
||||
- **Who it's for:** Satellite primes, payload integrators, avionics OEMs.
|
||||
- **Key benefits:** Space-qualified, low gate-count, well-documented, flight-proven.
|
||||
- **Features / what's included:** RTL block, verification IP, integration guide, optional support contract.
|
||||
- **Pricing model:** **[x] Custom quote**
|
||||
- **Price points:** Disclosed under NDA.
|
||||
- **Primary CTA:** "Request evaluation"
|
||||
- **Supporting proof:** Flight heritage on operational satellites.
|
||||
|
||||
### Offering 4 (Roadmap) — Custom AI ASIC Design Services
|
||||
- **What it is:** Custom silicon design for application-specific AI workloads. Not part of the launch site as a sellable product; presented on the Technology / Roadmap page as forward direction.
|
||||
|
||||
---
|
||||
|
||||
## 7. Brand Identity
|
||||
|
||||
### 7.1 Logo
|
||||
- **[x] We need a logo designed** — wordmark + symbol mark; symbol should reference parallelism / acceleration / orbit without being literal.
|
||||
|
||||
### 7.2 Color palette
|
||||
|
||||
| Role | Color | Hex | Notes |
|
||||
|---|---|---|---|
|
||||
| Primary | Deep Space Indigo | `#0B1437` | Dominant background; conveys depth, space, technical seriousness |
|
||||
| Secondary | Slate Navy | `#1A2347` | Cards, secondary surfaces |
|
||||
| Accent | Accelerate Cyan | `#00E5FF` | CTAs, links, highlights, data viz |
|
||||
| Neutral dark | Graphite | `#0E1118` | Headings on light, primary text on light |
|
||||
| Neutral light | Mist | `#F4F6FB` | Light-theme background, large surfaces |
|
||||
| Mid neutral | Steel | `#8A93A6` | Secondary text, captions, dividers |
|
||||
| Success | Signal Green | `#22C55E` | Form success, status pills |
|
||||
| Warning | Amber | `#F59E0B` | Inline warnings |
|
||||
| Error | Critical Red | `#EF4444` | Form errors |
|
||||
|
||||
Default theme: dark. A light theme is generated automatically (CSS variables) but is secondary.
|
||||
|
||||
### 7.3 Typography
|
||||
- **Heading font:** Inter (700 / 600)
|
||||
- **Body font:** Inter (400 / 500)
|
||||
- **Monospace:** JetBrains Mono — used for code blocks, datasheet numbers, and small "spec" pills
|
||||
|
||||
Type scale (rem): 0.75 · 0.875 · 1.0 · 1.125 · 1.25 · 1.5 · 1.875 · 2.25 · 3.0 · 3.75 · 4.5. Line-height 1.5 for body, 1.15 for display.
|
||||
|
||||
### 7.4 Imagery & illustration style
|
||||
- **[x] Custom illustration** — minimal, technical line art: chips, parallel data paths, orbital arcs. Two-tone (indigo + cyan).
|
||||
- **[x] 3D renders** — clean studio renders of chip / wafer hero visuals.
|
||||
- **[x] Photography** — small set of team photos (real, not staged) for the About page.
|
||||
- **[x] Icon-led** — stroke-style icons (Lucide) sized 16/20/24 px.
|
||||
|
||||
### 7.5 Voice & tone
|
||||
Top adjectives (5): **[x] Authoritative · [x] Technical · [x] Direct · [x] Bold · [x] Calm**
|
||||
|
||||
**Example phrases we'd say:**
|
||||
> "Accelerating the compute."
|
||||
> "Our IP has flown. Yours can too."
|
||||
> "Built in India, qualified in orbit."
|
||||
|
||||
**Example phrases we'd never say:**
|
||||
> "Synergy," "best-in-class," "leveraging cutting-edge solutions," "revolutionary game-changer."
|
||||
|
||||
### 7.6 Existing brand assets
|
||||
- [ ] Brand guidelines doc — to be produced from this document.
|
||||
- [ ] Logo files — to be designed.
|
||||
- [ ] Photography library — initial team shoot scheduled.
|
||||
- [ ] Existing website copy — none; greenfield.
|
||||
|
||||
---
|
||||
|
||||
## 8. Site Structure (Information Architecture)
|
||||
|
||||
### 8.1 Sitemap
|
||||
- **[x] Home**
|
||||
- **[x] About** — story, team, values
|
||||
- **[x] Team / Leadership** _(sub-section on About)_
|
||||
- **[x] Careers** _(linked from About and footer)_
|
||||
- **[x] Products** — overview
|
||||
- **[x] AI Inference IP Core**
|
||||
- **[x] Cybersecurity IP Core**
|
||||
- **[x] Communication Protocol IP Cores**
|
||||
- **[x] Technology** — architecture explainers, benchmarks, whitepapers
|
||||
- **[x] Blog / Insights** — technical posts, company news
|
||||
- **[x] Article template**
|
||||
- **[x] Category pages** (AI · Space · Robotics · Engineering · Company)
|
||||
- **[x] Press / News**
|
||||
- **[x] Contact** — also serves as "Request evaluation"
|
||||
- **[x] 404 page**
|
||||
- **[x] Thank-you pages** (post-form)
|
||||
- **[x] Privacy Policy**
|
||||
- **[x] Terms of Service**
|
||||
- **[x] Cookie Policy**
|
||||
- [ ] Pricing _(out of scope — quote-based, no public pricing)_
|
||||
- [ ] Partners _(out of scope at launch; revisit when partner programme is real)_
|
||||
- [ ] FAQ _(folded into product pages)_
|
||||
- [ ] Book a demo _(folded into the Contact / Request evaluation form)_
|
||||
|
||||
### 8.2 Primary navigation
|
||||
1. Products
|
||||
2. Technology
|
||||
3. About
|
||||
4. Careers
|
||||
5. **CTA button** — "Talk to us"
|
||||
|
||||
### 8.3 Footer
|
||||
- **[x] Mini sitemap** — Products · Technology · About · Careers · Blog · Contact
|
||||
- **[x] Contact info** — Surat HQ address, STIIC/IIST address, contact@risingcompute.in
|
||||
- **[x] Social links** — LinkedIn, X (Twitter), GitHub, YouTube _(YouTube placeholder until content exists)_
|
||||
- **[x] Newsletter signup** — single email field
|
||||
- **[x] Legal links** — Privacy · Terms · Cookies
|
||||
- **[x] Company registration** — "RisingCompute Pvt Ltd · CIN to be added · GSTIN to be added"
|
||||
- **[x] Incubation badge** — "Incubated at STIIC · IIST"
|
||||
|
||||
---
|
||||
|
||||
## 9. Page-by-Page Content Brief
|
||||
|
||||
### 9.1 Home
|
||||
- **Hero headline:** Accelerating the compute.
|
||||
- **Hero sub-headline:** Parallel hardware architectures and IP cores for AI, space, and robotics — designed in India, flown in orbit.
|
||||
- **Primary CTA:** "Talk to us" → /contact
|
||||
- **Secondary CTA:** "Read the architecture brief" → /technology
|
||||
- **Sections (in order):**
|
||||
1. **[x]** Hero with 3D chip render + animated parallel data paths
|
||||
2. **[x]** Social proof bar — IIST · STIIC · "Flight-heritage IP" pill
|
||||
3. **[x]** What we do — three product highlights (AI · Cybersecurity · Comms)
|
||||
4. **[x]** Why us / differentiators — flight heritage, sovereign IP, one-vendor stack
|
||||
5. **[x]** How it works — Evaluate → Integrate → Tape-out
|
||||
6. **[x]** Featured proof point — "Our IP has flown" with mission strip
|
||||
7. **[x]** Recent blog posts (3)
|
||||
8. **[x]** Final CTA block — "Start an evaluation" → /contact
|
||||
- **Key visuals needed:** Hero 3D chip render; animated SVG of parallel datapath; mission strip; engineer-at-workstation photo (Surat or IIST lab).
|
||||
|
||||
### 9.2 About
|
||||
- **Origin story:** Reuse §2.4 with photography of IIST and team.
|
||||
- **Founders section:** Three founder cards at the top of the team area — Ali Murabbi, Bhavy Savani, Abhishek Verma — each with portrait, role, domain, 80-word bio (see §2.6), and LinkedIn link.
|
||||
- **Team intro:** **[x] Full team grid** — 5 photos (3 founders + 2 early engineers), names, role, one-line bio, LinkedIn link.
|
||||
- **Values block:** §2.2 — Fast · Reliable · Robust as three icon cards.
|
||||
- **Office / culture photos:** **[x] Yes** — Surat office and STIIC/IIST.
|
||||
- **Press / awards row:** **[x] Yes** — placeholder slots until content exists.
|
||||
|
||||
### 9.3 Products / Services
|
||||
Each product page follows the same template:
|
||||
- Hero with the offering name + one-liner
|
||||
- The problem it solves (3 sentences)
|
||||
- How it works — block diagram + 4–6 features
|
||||
- What's included — bulleted deliverables (RTL, testbench, integration guide, etc.)
|
||||
- Indicative specs table (interface, throughput, gate count, target nodes / FPGAs)
|
||||
- "Request evaluation" CTA + secondary "Download datasheet" (gated)
|
||||
- 3-question FAQ specific to this product
|
||||
|
||||
### 9.4 Case Studies / Work
|
||||
- **Number of case studies at launch:** 0 published case studies; instead, a "Flight heritage" strip on the home and About pages noting that IP authored by the founding team has flown on satellite missions. Full case studies to be added as customers grant permission.
|
||||
|
||||
### 9.5 Pricing
|
||||
- **[x] "Contact us" only** — all IP is quote-based; pricing disclosed under NDA after a qualification call. No public pricing page.
|
||||
|
||||
### 9.6 Blog / Insights
|
||||
- **Launch with:** 4 posts.
|
||||
1. "Why we started RisingCompute" — founder note
|
||||
2. "What flight heritage actually means for IP cores"
|
||||
3. "Designing AI inference cores for INT8 without accuracy loss"
|
||||
4. "An Indian sovereign IP stack — and why it matters now"
|
||||
- **Categories:** AI · Space · Robotics · Engineering · Company
|
||||
- **Authors shown:** **[x] Yes**
|
||||
- **Comments enabled:** **[ ] No** — out of scope at launch
|
||||
- **Newsletter signup on every post:** **[x] Yes**
|
||||
|
||||
### 9.7 Contact
|
||||
- **[x] Contact form** — fields: Name, Work email, Company, Role, Country, Interest (dropdown: AI Inference IP · Cybersecurity IP · Communication IP · Custom ASIC · Careers · Press · Other), Message, How did you hear about us?
|
||||
- **[x] Direct email** — contact@risingcompute.in
|
||||
- **[x] Physical address + map** — Surat HQ + STIIC/IIST
|
||||
- **[x] Office hours** — Mon–Fri, 09:30–18:30 IST
|
||||
- [ ] Phone number _(not at launch; emails go to founder inbox)_
|
||||
- [ ] Calendly / booking link _(post-launch — added once a sales rhythm exists)_
|
||||
- [ ] Live chat widget _(not at launch)_
|
||||
|
||||
### 9.8 Other pages
|
||||
- **Technology page:** Architecture overview, benchmarks summary, links to downloadable whitepapers (gated).
|
||||
- **Careers page:** Mission, values, what it's like to work here, currently open roles (markdown-driven so non-engineers can edit), generic "no role but interested?" form.
|
||||
- **Press page:** Logos / awards / media mentions strip; downloadable press kit (logo pack + boilerplate).
|
||||
- **404:** Branded with a one-liner ("Lost in orbit. Let's get you back.") and links to top sections.
|
||||
- **Thank-you pages:** Per form (contact, newsletter, datasheet) with next-step suggestions.
|
||||
|
||||
---
|
||||
|
||||
## 10. Features & Functionality
|
||||
|
||||
**Lead capture & forms**
|
||||
- **[x]** Contact / "Request evaluation" form
|
||||
- **[x]** Datasheet download (gated — email required)
|
||||
- **[x]** Newsletter signup
|
||||
- **[x]** Careers application form (with file upload for CV)
|
||||
- [ ] Demo request form _(folded into contact form)_
|
||||
- [ ] Multi-step / progressive forms _(simple single-step at launch)_
|
||||
|
||||
**Content & engagement**
|
||||
- **[x]** Blog with categories & tags
|
||||
- **[x]** Search (across blog + technology pages)
|
||||
- **[x]** Filtering on blog by category
|
||||
- **[x]** Social share buttons (X, LinkedIn, copy link)
|
||||
- **[x]** RSS feed
|
||||
- [ ] Comments _(not at launch)_
|
||||
|
||||
**Booking & scheduling**
|
||||
- [ ] Calendly / Cal.com embed _(post-launch)_
|
||||
- [ ] Custom booking flow _(out of scope)_
|
||||
- [ ] Event RSVPs _(out of scope)_
|
||||
|
||||
**Commerce / payments** — _entirely out of scope_
|
||||
|
||||
**Authentication / portal**
|
||||
- [ ] Client login area _(post-launch — when first paying customer onboards)_
|
||||
- [ ] Document sharing portal _(post-launch)_
|
||||
|
||||
**Interactivity**
|
||||
- **[x]** Subtle animations / scroll effects
|
||||
- **[x]** Animated SVG datapath in hero
|
||||
- [ ] Video backgrounds _(too heavy at launch)_
|
||||
- [ ] Live chat / chatbot _(not at launch)_
|
||||
|
||||
**Localization**
|
||||
- **[x]** English only at launch; codebase prepared for future Hindi + Japanese.
|
||||
|
||||
**Other**
|
||||
- **[x]** Dark theme default with light-theme toggle
|
||||
- **[x]** Code-block syntax highlighting for technical blog posts
|
||||
- **[x]** OG image generation per post
|
||||
|
||||
---
|
||||
|
||||
## 11. Design Direction
|
||||
|
||||
### 11.1 Mood
|
||||
Top 3: **Technical · Bold · Futuristic** (with a strong supporting layer of **Calm** and **Spacious**).
|
||||
|
||||
### 11.2 Layout preferences
|
||||
- **Density:** **[x] Balanced** — spacious hero and product pages; denser technology and blog pages where engineers expect signal.
|
||||
- **Width:** **[x] Contained (max ~1280px)** with full-bleed feature bands.
|
||||
- **Page rhythm:** **[x] One idea per scroll-section** on marketing pages; magazine-style for blog index.
|
||||
|
||||
### 11.3 Motion & interactivity
|
||||
- **[x] Subtle** (fade-ins, hover states) + one **moderate** scroll-triggered hero animation. No parallax, no auto-play video, no WebGL at launch — performance and accessibility come first.
|
||||
|
||||
### 11.4 Devices to prioritize
|
||||
- **[x] Equal weight** mobile and desktop. Desktop is primary for B2B procurement reading; mobile must still render the home / product hero cleanly because LinkedIn traffic lands there.
|
||||
- **Browser support:** Modern evergreen — latest 2 versions of Chrome, Safari, Firefox, Edge. No IE.
|
||||
|
||||
---
|
||||
|
||||
## 12. Tech Stack
|
||||
|
||||
### 12.1 Frontend framework
|
||||
- **[x] Next.js 15 (App Router, React 19)** — the recommended choice; gives us per-route SSG/ISR, an excellent SEO story, image optimisation, and easy integration with MDX for the blog and datasheets.
|
||||
|
||||
### 12.2 Styling
|
||||
- **[x] Tailwind CSS** with a small set of CSS variables for the colour palette so a light theme is a single token swap. Component primitives via `class-variance-authority` and `clsx`.
|
||||
|
||||
### 12.3 CMS / Content management
|
||||
- **[x] Markdown / MDX in the repo** — fastest at this team size; product pages, blog, careers all editable in the repo. We will graduate to **Sanity** when the non-technical team is large enough to need an editor UI (revisit in 6 months).
|
||||
|
||||
### 12.4 Hosting & deployment
|
||||
- **[x] Vercel** — Next.js native, preview URLs per pull request, edge caching, free tier sufficient at launch.
|
||||
|
||||
### 12.5 Domain & DNS
|
||||
- **Existing domain:** risingcompute.in
|
||||
- **Registrar:** GoDaddy _(to be confirmed)_
|
||||
- **DNS provider:** **[x] Cloudflare** — moved from registrar to Cloudflare for free DNS, CDN, DDoS, and analytics.
|
||||
- **Email hosting:** Google Workspace — contact@risingcompute.in + individual founder addresses.
|
||||
|
||||
### 12.6 Forms backend
|
||||
- **[x] Next.js API route + Resend** for transactional email; submissions also posted to a Slack webhook for instant team visibility. Submissions stored in a Postgres table on Neon (free tier).
|
||||
- Spam protection via **[x] Cloudflare Turnstile** (privacy-friendlier than reCAPTCHA).
|
||||
|
||||
### 12.7 Repository & CI
|
||||
- **Code host:** **[x] GitHub** (organisation: `risingcompute`)
|
||||
- **CI/CD:** **[x] Vercel built-in** for the site; **GitHub Actions** for type-check, lint, and Lighthouse CI on every PR.
|
||||
- **Branching:** `main` is production; PR previews on every branch.
|
||||
|
||||
---
|
||||
|
||||
## 13. Integrations
|
||||
|
||||
**Analytics & attribution**
|
||||
- **[x] Plausible** — privacy-friendly, GDPR-ready out of the box, no cookie banner needed for analytics.
|
||||
- **[x] Microsoft Clarity** — free heatmaps & session recordings (with a clear privacy notice).
|
||||
- [ ] Google Analytics 4 _(skipped — privacy posture and cookie banner overhead)_
|
||||
|
||||
**Marketing & CRM**
|
||||
- **[x] Beehiiv** — newsletter (clean editor, generous free tier, good analytics).
|
||||
- [ ] HubSpot / Salesforce / Pipedrive _(deferred — form submissions go to a Notion CRM until volume justifies a real tool)_
|
||||
|
||||
**Communication**
|
||||
- **[x] Slack notifications on form submits** via webhook.
|
||||
- [ ] Live chat / Intercom _(not at launch)_
|
||||
|
||||
**Booking & payments**
|
||||
- [ ] Calendly / Cal.com _(post-launch)_
|
||||
- [ ] Stripe / PayPal _(out of scope — quote-based sales)_
|
||||
|
||||
**Other**
|
||||
- **[x] Cloudflare Turnstile** — form spam protection
|
||||
- **[x] Open Graph / Twitter card** image generation via `@vercel/og`
|
||||
- [ ] Algolia search _(skipped — local Pagefind index is sufficient)_
|
||||
- [ ] Google Tag Manager _(skipped — no need with Plausible)_
|
||||
|
||||
---
|
||||
|
||||
## 14. SEO & Content Strategy
|
||||
|
||||
### 14.1 Target keywords
|
||||
1. AI accelerator IP core
|
||||
2. AI inference IP
|
||||
3. FPGA IP cores India
|
||||
4. Space-grade IP core
|
||||
5. SpaceWire IP core
|
||||
6. Cybersecurity IP core
|
||||
7. Hardware AI acceleration India
|
||||
8. RISC-V AI accelerator
|
||||
9. Semiconductor startup India
|
||||
10. Edge AI hardware India
|
||||
11. Parallel computer architecture
|
||||
12. Robotics inference IP
|
||||
13. IIST startup
|
||||
14. ISRO IP vendor
|
||||
15. Make in India semiconductor IP
|
||||
|
||||
### 14.2 Per-page meta
|
||||
Every page sets unique title (≤60 chars) and description (≤155 chars). Must-haves:
|
||||
- **Home title:** "RisingCompute — Accelerating the compute"
|
||||
- **Home description:** "Parallel hardware architectures and IP cores for AI, space, and robotics. Designed in India, flown in orbit."
|
||||
- **About title:** "About RisingCompute — India's deep-tech IP company"
|
||||
- **Products / AI:** "AI Inference IP Core — RisingCompute"
|
||||
- **Products / Cybersecurity:** "Cybersecurity IP Core — RisingCompute"
|
||||
- **Products / Comms:** "Communication Protocol IP — RisingCompute"
|
||||
|
||||
### 14.3 Structured data
|
||||
- **[x]** Organization
|
||||
- **[x]** LocalBusiness (Surat HQ)
|
||||
- **[x]** Article (blog)
|
||||
- **[x]** FAQ (product page FAQs)
|
||||
- **[x]** Product (each IP core)
|
||||
- **[x]** BreadcrumbList
|
||||
|
||||
### 14.4 Redirects / migration
|
||||
- No existing site — greenfield. No 301 map required. `sitemap.xml` and `robots.txt` generated at build.
|
||||
|
||||
### 14.5 Content production
|
||||
- **Who writes the copy?** Founder team writes v1 of every page; we will engage a freelance technical editor for polish.
|
||||
- **Who edits the blog post-launch?** Founders and engineers; reviewed by Abhishek before publish.
|
||||
- **Cadence:** 2 posts per month for the first 6 months, then 1 per week.
|
||||
|
||||
---
|
||||
|
||||
## 15. Accessibility, Compliance & Legal
|
||||
|
||||
### 15.1 Accessibility
|
||||
- **[x] WCAG 2.1 AA** target — colour contrast verified for both themes; keyboard nav and visible focus on every interactive element; alt text on every image; semantic landmarks.
|
||||
|
||||
### 15.2 Privacy & data
|
||||
- **Visitors from EU/UK?** **[x] Yes** — GDPR applies.
|
||||
- **Visitors from California?** **[x] Yes** — CCPA applies.
|
||||
- **[x] Cookie consent banner** — minimal banner because analytics is cookie-free; banner appears only if Microsoft Clarity is enabled (deferred-load with consent).
|
||||
- **[x] Need privacy policy written** — drafted before launch (template + lawyer review).
|
||||
- **[x] Need ToS written** — drafted before launch.
|
||||
- **Data controller / DPO contact:** Abhishek Verma — privacy@risingcompute.in
|
||||
|
||||
### 15.3 Industry-specific
|
||||
- [ ] Healthcare (HIPAA) — not applicable
|
||||
- [ ] Finance / banking — not applicable
|
||||
- [ ] Children's products (COPPA) — not applicable
|
||||
- **Export-control note:** Some IP cores may be subject to dual-use export-control review. The site does not publish export-controlled information; gated downloads include an acknowledgement step.
|
||||
|
||||
---
|
||||
|
||||
## 16. Performance & Quality Bar
|
||||
|
||||
### 16.1 Performance targets
|
||||
- **[x] Lighthouse 95+** on mobile across Performance, Accessibility, Best Practices, SEO.
|
||||
- **[x] Core Web Vitals "good"** — LCP < 2.0 s, CLS < 0.05, INP < 150 ms.
|
||||
- **[x] Landing-page weight under 500 KB** above the fold (incl. fonts and hero).
|
||||
|
||||
### 16.2 Browser support
|
||||
- Modern Chrome, Safari, Firefox, Edge — last 2 versions. No IE.
|
||||
|
||||
### 16.3 Quality assurance
|
||||
- **[x]** Cross-browser testing — BrowserStack covering top 5 device/browser combos.
|
||||
- **[x]** Mobile device testing — iOS Safari (iPhone 13+), Android Chrome (Pixel 6+).
|
||||
- **[x]** Accessibility audit — `axe-core` automated in CI + manual screen-reader sweep (NVDA + VoiceOver).
|
||||
- **[x]** Performance audit — Lighthouse CI gate on every PR; WebPageTest before launch.
|
||||
- **[x]** SEO audit pre-launch — Screaming Frog + manual structured-data validation.
|
||||
- **[x]** Link check — `lychee` link checker in CI.
|
||||
|
||||
---
|
||||
|
||||
## 17. Timeline & Milestones
|
||||
|
||||
| Milestone | Target date | Owner |
|
||||
|---|---|---|
|
||||
| Design document signed off | 22 May 2026 | Abhishek Verma |
|
||||
| Wireframes approved | 29 May 2026 | Abhishek Verma |
|
||||
| Visual designs approved | 5 June 2026 | Abhishek Verma |
|
||||
| Content (copy + photography) delivered | 12 June 2026 | Founding team |
|
||||
| Development complete | 22 June 2026 | Engineering |
|
||||
| QA / UAT | 23–26 June 2026 | Abhishek Verma |
|
||||
| Soft launch / staging review | 28 June 2026 | Founding team |
|
||||
| **Public launch** | **30 June 2026** | Abhishek Verma |
|
||||
|
||||
---
|
||||
|
||||
## 18. Budget
|
||||
|
||||
| Bucket | Estimate (INR) | Notes |
|
||||
|---|---|---|
|
||||
| Design | ₹0 | In-house (founding team) |
|
||||
| Development | ₹0 | In-house (founding team) |
|
||||
| Copywriting | ₹0 | Founders draft; editor on retainer if needed |
|
||||
| Photography / illustration | ₹10,000 | One-day team shoot in Surat |
|
||||
| Domain renewal | ₹1,500 / yr | risingcompute.in |
|
||||
| Hosting (Vercel) | ₹0 | Free tier sufficient at launch |
|
||||
| DNS / CDN (Cloudflare) | ₹0 | Free tier |
|
||||
| Email (Google Workspace) | ₹2,500 / month | 5 seats |
|
||||
| Newsletter (Beehiiv) | ₹0 | Free tier up to 2,500 subs |
|
||||
| Analytics (Plausible) | ₹750 / month | Cheapest tier |
|
||||
| Database (Neon) | ₹0 | Free tier sufficient at launch |
|
||||
| Email sender (Resend) | ₹0 | Free tier sufficient |
|
||||
| Legal review (Privacy / ToS) | ₹15,000 | One-off, local counsel |
|
||||
| Contingency | ₹5,000 | — |
|
||||
| **Total one-off** | **~₹31,500** | |
|
||||
| **Total monthly recurring** | **~₹3,250** | (Workspace + analytics) |
|
||||
|
||||
---
|
||||
|
||||
## 19. Post-Launch: Maintenance & Growth
|
||||
|
||||
### 19.1 Ownership after launch
|
||||
- **Day-to-day content edits:** Abhishek Verma (founder) — markdown PRs.
|
||||
- **Bug fixes & dev support:** Engineering team (rotation).
|
||||
- **Hosting & DNS:** Abhishek Verma.
|
||||
- **SEO & analytics review:** Monthly, Abhishek Verma.
|
||||
|
||||
### 19.2 Ongoing work
|
||||
- **[x] Monthly performance / analytics review** — first Monday of each month.
|
||||
- **[x] Quarterly content refresh** — product pages, team grid, press.
|
||||
- **[x] Annual design review** — May each year.
|
||||
- **[x] SEO / content marketing** — in-house at launch; revisit retainer once posts hit 50.
|
||||
- [ ] Paid acquisition — not at launch; reconsider post-fundraise.
|
||||
|
||||
### 19.3 Roadmap (post-launch features)
|
||||
1. Customer / partner login portal for licensees (datasheet repository, ticketing).
|
||||
2. Interactive datapath / benchmark visualiser on the Technology page.
|
||||
3. Sanity CMS migration once non-technical editors join.
|
||||
4. Hindi + Japanese localisation.
|
||||
5. Calendly integration once the founder calendar saturates.
|
||||
6. Customer case-study collection programme (with permission).
|
||||
7. Public talks / events calendar.
|
||||
|
||||
---
|
||||
|
||||
## 20. Stakeholders & Approvals
|
||||
|
||||
| Name | Role | Email | Sign-off needed on |
|
||||
|---|---|---|---|
|
||||
| Abhishek Verma | Co-founder · System Engineer & Project Manager · Project sponsor | contact@risingcompute.in | Final launch, copy, system architecture, integrations, privacy / legal |
|
||||
| Bhavy Savani | Co-founder · VLSI & AI Engineer | _(to be added)_ | AI Inference IP page, Cybersecurity IP page, technical accuracy of benchmarks |
|
||||
| Ali Murabbi | Co-founder · VLSI & Robotics Engineer | _(to be added)_ | Communication IP page, robotics positioning, RTL specs |
|
||||
| External counsel _(name TBC)_ | Legal / compliance | _(to be added)_ | Privacy Policy, ToS, export-control language |
|
||||
| External designer _(name TBC)_ | Brand / Visual | _(to be added)_ | Logo, visual identity |
|
||||
|
||||
---
|
||||
|
||||
## 21. Open Questions & Risks
|
||||
|
||||
- **[ ] Logo & brand identity not yet designed** — risk to launch date. Owner: Abhishek Verma. Due: 29 May 2026.
|
||||
- **[ ] Founder bios + team photos not yet collected** — blocks About page content. Owner: Abhishek Verma. Due: 12 June 2026.
|
||||
- **[ ] Datasheets need a "public" version (no controlled material)** — blocks gated download flow. Owner: Engineering. Due: 19 June 2026.
|
||||
- **[ ] Export-control language sign-off** — needs counsel review before gated downloads go live. Owner: External counsel. Due: 22 June 2026.
|
||||
- **[ ] Benchmarks for AI Inference IP page** — need at least one published comparison vs. a public baseline. Owner: Engineering. Due: 19 June 2026.
|
||||
- **[ ] Press kit (logo pack + boilerplate)** — needed for Press page. Owner: Abhishek Verma. Due: 26 June 2026.
|
||||
|
||||
---
|
||||
|
||||
## 22. Appendix: Asset Checklist
|
||||
|
||||
Before development starts, gather these:
|
||||
- [ ] Logo (SVG + PNG, light + dark variants) — to be designed
|
||||
- [ ] Brand guidelines doc — to be produced from this document
|
||||
- [ ] High-res photography — team (5 portraits + group), Surat office, IIST lab — one-day shoot
|
||||
- [ ] Mission strip imagery — satellite or launch photo we have rights to use
|
||||
- [ ] Block diagrams — one per IP core (AI Inference, Cybersecurity, Comms)
|
||||
- [ ] Founder bios — 80-word version of each, with LinkedIn link
|
||||
- [ ] Press kit ZIP — logo pack, one-page company fact-sheet, founder photos
|
||||
- [ ] Social media handles — LinkedIn, X, GitHub, YouTube (placeholder)
|
||||
- [ ] Office address card — Surat HQ + STIIC/IIST
|
||||
- [ ] Legal entity details — CIN, GSTIN once issued
|
||||
- [ ] Privacy Policy + Terms of Service — drafted and reviewed by counsel
|
||||
- [ ] Cookie Policy — drafted (short — analytics is cookie-free, Clarity is consent-gated)
|
||||
|
||||
---
|
||||
|
||||
_End of document. This is the final, build-ready specification for risingcompute.in. Any change after sign-off is logged in §0._
|
||||
5
frontend/.env.example
Normal file
5
frontend/.env.example
Normal file
@@ -0,0 +1,5 @@
|
||||
# Frontend env — copy to `.env` (or `.env.local`).
|
||||
# Dev: leave empty to use the Vite proxy → http://127.0.0.1:8000
|
||||
# Prod: set the absolute API base, e.g. https://risingcompute.in
|
||||
VITE_API_BASE_URL=
|
||||
VITE_API_PROXY=http://127.0.0.1:8000
|
||||
31
frontend/index.html
Normal file
31
frontend/index.html
Normal file
@@ -0,0 +1,31 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta name="theme-color" content="#0B1437" />
|
||||
<meta
|
||||
name="description"
|
||||
content="RisingCompute — parallel hardware architectures and IP cores for AI, space, and robotics. Designed in India, flown in orbit."
|
||||
/>
|
||||
<meta property="og:title" content="RisingCompute — Accelerating the compute" />
|
||||
<meta
|
||||
property="og:description"
|
||||
content="Parallel hardware architectures and IP cores for AI, space, and robotics."
|
||||
/>
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:url" content="https://risingcompute.in" />
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<title>RisingCompute — Accelerating the compute</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
20
frontend/package.json
Normal file
20
frontend/package.json
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"name": "risingcompute-web",
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview --port 4173"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^1.7.2",
|
||||
"vue": "^3.4.27",
|
||||
"vue-router": "^4.3.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-vue": "^5.0.5",
|
||||
"vite": "^5.2.13"
|
||||
}
|
||||
}
|
||||
10
frontend/public/favicon.svg
Normal file
10
frontend/public/favicon.svg
Normal file
@@ -0,0 +1,10 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
|
||||
<defs>
|
||||
<linearGradient id="g" x1="0" y1="0" x2="1" y2="1">
|
||||
<stop offset="0%" stop-color="#0B1437"/>
|
||||
<stop offset="100%" stop-color="#00E5FF"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<rect width="64" height="64" rx="14" fill="url(#g)"/>
|
||||
<path d="M16 44 L26 28 L36 38 L48 18" stroke="#F4F6FB" stroke-width="4" fill="none" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 452 B |
23
frontend/src/App.vue
Normal file
23
frontend/src/App.vue
Normal file
@@ -0,0 +1,23 @@
|
||||
<script setup>
|
||||
import TheHeader from '@/components/TheHeader.vue'
|
||||
import TheFooter from '@/components/TheFooter.vue'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<TheHeader />
|
||||
<main>
|
||||
<RouterView v-slot="{ Component }">
|
||||
<transition name="route-fade" mode="out-in">
|
||||
<component :is="Component" />
|
||||
</transition>
|
||||
</RouterView>
|
||||
</main>
|
||||
<TheFooter />
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
main {
|
||||
flex: 1;
|
||||
padding-top: var(--nav-height);
|
||||
}
|
||||
</style>
|
||||
32
frontend/src/api/client.js
Normal file
32
frontend/src/api/client.js
Normal file
@@ -0,0 +1,32 @@
|
||||
import axios from 'axios'
|
||||
|
||||
// In dev, leave VITE_API_BASE_URL empty and let Vite proxy /api → Django.
|
||||
// In prod, set VITE_API_BASE_URL=https://api.risingcompute.in (or same origin).
|
||||
const baseURL = (import.meta.env.VITE_API_BASE_URL || '') + '/api'
|
||||
|
||||
const client = axios.create({
|
||||
baseURL,
|
||||
timeout: 15000,
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
})
|
||||
|
||||
export const api = {
|
||||
// Content
|
||||
listProducts: () => client.get('/products/').then(r => r.data),
|
||||
getProduct: (slug) => client.get(`/products/${slug}/`).then(r => r.data),
|
||||
listFounders: () => client.get('/founders/').then(r => r.data),
|
||||
listPosts: () => client.get('/posts/').then(r => r.data),
|
||||
getPost: (slug) => client.get(`/posts/${slug}/`).then(r => r.data),
|
||||
listJobs: () => client.get('/jobs/').then(r => r.data),
|
||||
|
||||
// Submissions
|
||||
submitContact: (payload) => client.post('/contact/', payload).then(r => r.data),
|
||||
subscribeNewsletter: (email, source = '') =>
|
||||
client.post('/newsletter/', { email, source }).then(r => r.data),
|
||||
submitApplication: (formData) =>
|
||||
client.post('/apply/', formData, {
|
||||
headers: { 'Content-Type': 'multipart/form-data' },
|
||||
}).then(r => r.data),
|
||||
}
|
||||
|
||||
export default client
|
||||
342
frontend/src/assets/styles/main.css
Normal file
342
frontend/src/assets/styles/main.css
Normal file
@@ -0,0 +1,342 @@
|
||||
/* ===================================================================
|
||||
* RisingCompute — Design tokens & base styles
|
||||
* Brand: Fast · Reliable · Robust
|
||||
* Dark theme by default. Indigo + Cyan + minimal motion.
|
||||
* =================================================================== */
|
||||
|
||||
:root {
|
||||
/* Brand palette — see design-document §7.2 */
|
||||
--color-bg: #0B1437; /* Deep Space Indigo */
|
||||
--color-bg-soft: #111B47;
|
||||
--color-surface: #1A2347; /* Slate Navy — cards */
|
||||
--color-surface-2: #232C57;
|
||||
--color-border: #2A3463;
|
||||
--color-border-soft: #1F2750;
|
||||
|
||||
--color-text: #F4F6FB; /* Mist */
|
||||
--color-text-muted: #B6BED2;
|
||||
--color-text-dim: #8A93A6; /* Steel */
|
||||
|
||||
--color-accent: #00E5FF; /* Accelerate Cyan */
|
||||
--color-accent-soft: rgba(0, 229, 255, 0.16);
|
||||
--color-accent-glow: rgba(0, 229, 255, 0.35);
|
||||
|
||||
--color-success: #22C55E;
|
||||
--color-warning: #F59E0B;
|
||||
--color-error: #EF4444;
|
||||
|
||||
/* Typography */
|
||||
--font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
||||
--font-mono: 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
||||
|
||||
/* Spacing scale */
|
||||
--space-1: 0.25rem;
|
||||
--space-2: 0.5rem;
|
||||
--space-3: 0.75rem;
|
||||
--space-4: 1rem;
|
||||
--space-5: 1.5rem;
|
||||
--space-6: 2rem;
|
||||
--space-7: 3rem;
|
||||
--space-8: 4rem;
|
||||
--space-9: 6rem;
|
||||
--space-10: 8rem;
|
||||
|
||||
/* Radii */
|
||||
--radius-sm: 6px;
|
||||
--radius-md: 10px;
|
||||
--radius-lg: 16px;
|
||||
--radius-xl: 22px;
|
||||
|
||||
/* Layout */
|
||||
--max-content: 1240px;
|
||||
--nav-height: 72px;
|
||||
|
||||
/* Motion */
|
||||
--ease-out: cubic-bezier(0.16, 1, 0.3, 1);
|
||||
--transition-fast: 120ms var(--ease-out);
|
||||
--transition: 220ms var(--ease-out);
|
||||
--transition-slow: 420ms var(--ease-out);
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html {
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
|
||||
html, body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background: var(--color-bg);
|
||||
color: var(--color-text);
|
||||
font-family: var(--font-sans);
|
||||
font-size: 16px;
|
||||
line-height: 1.6;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
text-rendering: optimizeLegibility;
|
||||
}
|
||||
|
||||
body {
|
||||
background:
|
||||
radial-gradient(1100px 600px at 80% -10%, rgba(0, 229, 255, 0.08), transparent 60%),
|
||||
radial-gradient(900px 500px at 0% 0%, rgba(100, 120, 255, 0.06), transparent 60%),
|
||||
var(--color-bg);
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
#app {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
/* ---------- Typography ---------- */
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
font-family: var(--font-sans);
|
||||
font-weight: 600;
|
||||
line-height: 1.15;
|
||||
letter-spacing: -0.02em;
|
||||
margin: 0 0 var(--space-4);
|
||||
color: var(--color-text);
|
||||
}
|
||||
h1 { font-size: clamp(2.25rem, 5vw, 3.75rem); font-weight: 700; letter-spacing: -0.03em; }
|
||||
h2 { font-size: clamp(1.75rem, 3vw, 2.5rem); }
|
||||
h3 { font-size: 1.5rem; }
|
||||
h4 { font-size: 1.25rem; }
|
||||
|
||||
p { margin: 0 0 var(--space-4); color: var(--color-text-muted); }
|
||||
small { color: var(--color-text-dim); }
|
||||
|
||||
a {
|
||||
color: var(--color-accent);
|
||||
text-decoration: none;
|
||||
transition: color var(--transition-fast);
|
||||
}
|
||||
a:hover { color: var(--color-text); }
|
||||
|
||||
code, pre, kbd {
|
||||
font-family: var(--font-mono);
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
/* ---------- Layout ---------- */
|
||||
.container {
|
||||
width: 100%;
|
||||
max-width: var(--max-content);
|
||||
margin: 0 auto;
|
||||
padding: 0 var(--space-5);
|
||||
}
|
||||
|
||||
.section {
|
||||
padding: var(--space-9) 0;
|
||||
}
|
||||
.section--tight { padding: var(--space-7) 0; }
|
||||
|
||||
.eyebrow {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: var(--space-2);
|
||||
font-family: var(--font-mono);
|
||||
font-size: 0.75rem;
|
||||
font-weight: 500;
|
||||
letter-spacing: 0.1em;
|
||||
text-transform: uppercase;
|
||||
color: var(--color-accent);
|
||||
}
|
||||
.eyebrow::before {
|
||||
content: '';
|
||||
display: inline-block;
|
||||
width: 10px;
|
||||
height: 1px;
|
||||
background: var(--color-accent);
|
||||
}
|
||||
|
||||
/* ---------- Buttons ---------- */
|
||||
.btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: var(--space-2);
|
||||
font-family: var(--font-sans);
|
||||
font-weight: 500;
|
||||
font-size: 0.95rem;
|
||||
line-height: 1;
|
||||
padding: 0.85rem 1.4rem;
|
||||
border-radius: var(--radius-md);
|
||||
border: 1px solid transparent;
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
transition: all var(--transition);
|
||||
white-space: nowrap;
|
||||
}
|
||||
.btn:focus-visible {
|
||||
outline: 2px solid var(--color-accent);
|
||||
outline-offset: 3px;
|
||||
}
|
||||
|
||||
.btn--primary {
|
||||
background: var(--color-accent);
|
||||
color: #001722;
|
||||
font-weight: 600;
|
||||
}
|
||||
.btn--primary:hover {
|
||||
background: #5BF0FF;
|
||||
box-shadow: 0 8px 28px -8px var(--color-accent-glow);
|
||||
color: #001722;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.btn--ghost {
|
||||
background: transparent;
|
||||
color: var(--color-text);
|
||||
border-color: var(--color-border);
|
||||
}
|
||||
.btn--ghost:hover {
|
||||
border-color: var(--color-accent);
|
||||
color: var(--color-accent);
|
||||
}
|
||||
|
||||
.btn--link {
|
||||
background: transparent;
|
||||
padding: 0;
|
||||
color: var(--color-accent);
|
||||
}
|
||||
.btn--link:hover { color: var(--color-text); }
|
||||
|
||||
.btn--full { width: 100%; }
|
||||
|
||||
/* ---------- Cards ---------- */
|
||||
.card {
|
||||
background: linear-gradient(180deg, var(--color-surface) 0%, var(--color-surface-2) 100%);
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: var(--space-6);
|
||||
transition: border-color var(--transition), transform var(--transition);
|
||||
}
|
||||
.card:hover {
|
||||
border-color: rgba(0, 229, 255, 0.35);
|
||||
transform: translateY(-3px);
|
||||
}
|
||||
|
||||
/* ---------- Forms ---------- */
|
||||
.field {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-2);
|
||||
margin-bottom: var(--space-4);
|
||||
}
|
||||
.field label {
|
||||
font-size: 0.85rem;
|
||||
color: var(--color-text-muted);
|
||||
font-weight: 500;
|
||||
}
|
||||
.field input,
|
||||
.field select,
|
||||
.field textarea {
|
||||
width: 100%;
|
||||
background: var(--color-bg-soft);
|
||||
color: var(--color-text);
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-md);
|
||||
padding: 0.8rem 1rem;
|
||||
font-family: var(--font-sans);
|
||||
font-size: 0.95rem;
|
||||
transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
|
||||
}
|
||||
.field input::placeholder,
|
||||
.field textarea::placeholder { color: var(--color-text-dim); }
|
||||
.field input:focus,
|
||||
.field select:focus,
|
||||
.field textarea:focus {
|
||||
outline: none;
|
||||
border-color: var(--color-accent);
|
||||
box-shadow: 0 0 0 3px var(--color-accent-soft);
|
||||
}
|
||||
.field textarea {
|
||||
min-height: 140px;
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
.form-row {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: var(--space-4);
|
||||
}
|
||||
@media (max-width: 640px) {
|
||||
.form-row { grid-template-columns: 1fr; }
|
||||
}
|
||||
|
||||
.form-error {
|
||||
color: var(--color-error);
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
.form-success {
|
||||
background: rgba(34, 197, 94, 0.1);
|
||||
border: 1px solid rgba(34, 197, 94, 0.35);
|
||||
color: var(--color-success);
|
||||
padding: var(--space-4);
|
||||
border-radius: var(--radius-md);
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
|
||||
/* ---------- Pills / Tags ---------- */
|
||||
.pill {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: var(--space-2);
|
||||
padding: 0.3rem 0.7rem;
|
||||
border-radius: 999px;
|
||||
font-family: var(--font-mono);
|
||||
font-size: 0.72rem;
|
||||
font-weight: 500;
|
||||
letter-spacing: 0.05em;
|
||||
text-transform: uppercase;
|
||||
background: var(--color-accent-soft);
|
||||
color: var(--color-accent);
|
||||
border: 1px solid rgba(0, 229, 255, 0.25);
|
||||
}
|
||||
|
||||
/* ---------- Grids ---------- */
|
||||
.grid {
|
||||
display: grid;
|
||||
gap: var(--space-5);
|
||||
}
|
||||
.grid--3 { grid-template-columns: repeat(3, 1fr); }
|
||||
.grid--2 { grid-template-columns: repeat(2, 1fr); }
|
||||
@media (max-width: 900px) {
|
||||
.grid--3, .grid--2 { grid-template-columns: 1fr; }
|
||||
}
|
||||
|
||||
/* ---------- Page transitions ---------- */
|
||||
.route-fade-enter-active,
|
||||
.route-fade-leave-active {
|
||||
transition: opacity 200ms var(--ease-out);
|
||||
}
|
||||
.route-fade-enter-from,
|
||||
.route-fade-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
/* ---------- Utility ---------- */
|
||||
.text-center { text-align: center; }
|
||||
.muted { color: var(--color-text-muted); }
|
||||
.dim { color: var(--color-text-dim); }
|
||||
.mono { font-family: var(--font-mono); }
|
||||
|
||||
.divider {
|
||||
height: 1px;
|
||||
background: linear-gradient(90deg, transparent, var(--color-border), transparent);
|
||||
margin: var(--space-7) 0;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
/* Reduce motion for users who request it */
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
*, *::before, *::after {
|
||||
animation-duration: 0.001ms !important;
|
||||
transition-duration: 0.001ms !important;
|
||||
}
|
||||
}
|
||||
129
frontend/src/components/ContactForm.vue
Normal file
129
frontend/src/components/ContactForm.vue
Normal file
@@ -0,0 +1,129 @@
|
||||
<script setup>
|
||||
import { reactive, ref } from 'vue'
|
||||
import { api } from '@/api/client'
|
||||
|
||||
const props = defineProps({
|
||||
defaultInterest: { type: String, default: 'other' },
|
||||
})
|
||||
|
||||
const form = reactive({
|
||||
name: '',
|
||||
email: '',
|
||||
company: '',
|
||||
role: '',
|
||||
country: '',
|
||||
interest: props.defaultInterest,
|
||||
message: '',
|
||||
referrer: typeof document !== 'undefined' ? document.referrer : '',
|
||||
})
|
||||
|
||||
const status = ref('idle') // idle | loading | success | error
|
||||
const errors = ref({})
|
||||
const errorMessage = ref('')
|
||||
|
||||
async function submit() {
|
||||
status.value = 'loading'
|
||||
errors.value = {}
|
||||
errorMessage.value = ''
|
||||
try {
|
||||
await api.submitContact(form)
|
||||
status.value = 'success'
|
||||
} catch (err) {
|
||||
status.value = 'error'
|
||||
if (err.response?.data && typeof err.response.data === 'object') {
|
||||
errors.value = err.response.data
|
||||
errorMessage.value = 'Please check the fields below.'
|
||||
} else {
|
||||
errorMessage.value = 'Something went wrong. Please try again.'
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<form class="contact-form" @submit.prevent="submit" novalidate>
|
||||
<template v-if="status !== 'success'">
|
||||
<div class="form-row">
|
||||
<div class="field">
|
||||
<label for="cf-name">Name</label>
|
||||
<input id="cf-name" v-model="form.name" type="text" required autocomplete="name" />
|
||||
<span v-if="errors.name" class="form-error">{{ errors.name[0] }}</span>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="cf-email">Work email</label>
|
||||
<input id="cf-email" v-model="form.email" type="email" required autocomplete="email" />
|
||||
<span v-if="errors.email" class="form-error">{{ errors.email[0] }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<div class="field">
|
||||
<label for="cf-company">Company</label>
|
||||
<input id="cf-company" v-model="form.company" type="text" autocomplete="organization" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="cf-role">Role</label>
|
||||
<input id="cf-role" v-model="form.role" type="text" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<div class="field">
|
||||
<label for="cf-country">Country</label>
|
||||
<input id="cf-country" v-model="form.country" type="text" autocomplete="country-name" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="cf-interest">Interest</label>
|
||||
<select id="cf-interest" v-model="form.interest">
|
||||
<option value="ai-ip">AI Inference IP</option>
|
||||
<option value="security-ip">Cybersecurity IP</option>
|
||||
<option value="comms-ip">Communication IP</option>
|
||||
<option value="custom-asic">Custom ASIC</option>
|
||||
<option value="careers">Careers</option>
|
||||
<option value="press">Press</option>
|
||||
<option value="other">Other</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<label for="cf-message">What are you looking for?</label>
|
||||
<textarea
|
||||
id="cf-message"
|
||||
v-model="form.message"
|
||||
required
|
||||
placeholder="A few lines about the project, target node / FPGA, and timeline."
|
||||
></textarea>
|
||||
<span v-if="errors.message" class="form-error">{{ errors.message[0] }}</span>
|
||||
</div>
|
||||
|
||||
<p v-if="errorMessage" class="form-error">{{ errorMessage }}</p>
|
||||
|
||||
<button type="submit" class="btn btn--primary btn--full" :disabled="status === 'loading'">
|
||||
{{ status === 'loading' ? 'Sending…' : 'Send enquiry' }}
|
||||
</button>
|
||||
<p class="dim contact-form__legal">
|
||||
We typically reply within one business day. By submitting, you agree to be
|
||||
contacted about your enquiry.
|
||||
</p>
|
||||
</template>
|
||||
|
||||
<div v-else class="form-success">
|
||||
<h3>Thanks — message received.</h3>
|
||||
<p>One of the founders will follow up at <strong>{{ form.email }}</strong> within one business day.</p>
|
||||
</div>
|
||||
</form>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.contact-form {
|
||||
background: linear-gradient(180deg, var(--color-surface), var(--color-surface-2));
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: var(--space-6);
|
||||
}
|
||||
.contact-form__legal {
|
||||
font-size: 0.78rem;
|
||||
margin: var(--space-3) 0 0;
|
||||
}
|
||||
</style>
|
||||
72
frontend/src/components/FounderCard.vue
Normal file
72
frontend/src/components/FounderCard.vue
Normal file
@@ -0,0 +1,72 @@
|
||||
<script setup>
|
||||
defineProps({
|
||||
founder: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
})
|
||||
|
||||
function initials(name) {
|
||||
return name.split(' ').map(p => p[0]).slice(0, 2).join('').toUpperCase()
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<article class="founder">
|
||||
<div class="founder__avatar" :aria-hidden="!!founder.photo_url">
|
||||
<img v-if="founder.photo_url" :src="founder.photo_url" :alt="founder.name" />
|
||||
<span v-else>{{ initials(founder.name) }}</span>
|
||||
</div>
|
||||
<h3 class="founder__name">{{ founder.name }}</h3>
|
||||
<p class="founder__role">{{ founder.role }}</p>
|
||||
<p class="founder__domain mono">{{ founder.domain }}</p>
|
||||
<p class="founder__bio">{{ founder.bio }}</p>
|
||||
<a v-if="founder.linkedin_url" :href="founder.linkedin_url" target="_blank" rel="noopener" class="btn--link">
|
||||
LinkedIn ↗
|
||||
</a>
|
||||
</article>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.founder {
|
||||
background: linear-gradient(180deg, var(--color-surface), var(--color-surface-2));
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: var(--space-6);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-3);
|
||||
transition: border-color var(--transition), transform var(--transition);
|
||||
}
|
||||
.founder:hover {
|
||||
border-color: rgba(0, 229, 255, 0.35);
|
||||
transform: translateY(-3px);
|
||||
}
|
||||
.founder__avatar {
|
||||
width: 72px;
|
||||
height: 72px;
|
||||
border-radius: 50%;
|
||||
background: linear-gradient(135deg, var(--color-accent-soft), rgba(11, 20, 55, 0.6));
|
||||
border: 1px solid var(--color-border);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: var(--color-accent);
|
||||
font-family: var(--font-mono);
|
||||
font-size: 1.1rem;
|
||||
font-weight: 600;
|
||||
overflow: hidden;
|
||||
}
|
||||
.founder__avatar img {
|
||||
width: 100%; height: 100%; object-fit: cover;
|
||||
}
|
||||
.founder__name { margin: 0; font-size: 1.25rem; }
|
||||
.founder__role { color: var(--color-accent); font-size: 0.9rem; margin: 0; font-weight: 500; }
|
||||
.founder__domain {
|
||||
color: var(--color-text-dim);
|
||||
font-size: 0.78rem;
|
||||
letter-spacing: 0.04em;
|
||||
margin: 0;
|
||||
}
|
||||
.founder__bio { color: var(--color-text-muted); margin: 0; }
|
||||
</style>
|
||||
75
frontend/src/components/ProductCard.vue
Normal file
75
frontend/src/components/ProductCard.vue
Normal file
@@ -0,0 +1,75 @@
|
||||
<script setup>
|
||||
import { RouterLink } from 'vue-router'
|
||||
|
||||
defineProps({
|
||||
product: { type: Object, required: true },
|
||||
})
|
||||
|
||||
const iconMap = {
|
||||
ai: '∿',
|
||||
security: '⌬',
|
||||
comms: '⤬',
|
||||
asic: '◇',
|
||||
other: '◍',
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<RouterLink :to="`/products/${product.slug}`" class="product">
|
||||
<div class="product__head">
|
||||
<span class="product__icon mono">{{ iconMap[product.category] || '◍' }}</span>
|
||||
<span class="pill">{{ product.category_label }}</span>
|
||||
</div>
|
||||
<h3 class="product__name">{{ product.name }}</h3>
|
||||
<p class="product__tagline">{{ product.tagline }}</p>
|
||||
<p class="product__summary">{{ product.summary }}</p>
|
||||
<span class="product__more">Read more →</span>
|
||||
</RouterLink>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.product {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-3);
|
||||
background: linear-gradient(180deg, var(--color-surface), var(--color-surface-2));
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: var(--space-6);
|
||||
color: var(--color-text);
|
||||
transition: border-color var(--transition), transform var(--transition);
|
||||
height: 100%;
|
||||
}
|
||||
.product:hover {
|
||||
border-color: rgba(0, 229, 255, 0.4);
|
||||
transform: translateY(-3px);
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
.product__head {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: var(--space-2);
|
||||
}
|
||||
.product__icon {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 44px; height: 44px;
|
||||
border-radius: var(--radius-md);
|
||||
background: var(--color-accent-soft);
|
||||
color: var(--color-accent);
|
||||
font-size: 1.5rem;
|
||||
border: 1px solid rgba(0, 229, 255, 0.25);
|
||||
}
|
||||
.product__name { margin: 0; font-size: 1.3rem; }
|
||||
.product__tagline { color: var(--color-accent); font-size: 0.95rem; margin: 0; }
|
||||
.product__summary { color: var(--color-text-muted); margin: 0; flex: 1; }
|
||||
.product__more {
|
||||
color: var(--color-accent);
|
||||
font-size: 0.9rem;
|
||||
font-weight: 500;
|
||||
margin-top: var(--space-2);
|
||||
}
|
||||
</style>
|
||||
32
frontend/src/components/SectionHero.vue
Normal file
32
frontend/src/components/SectionHero.vue
Normal file
@@ -0,0 +1,32 @@
|
||||
<script setup>
|
||||
defineProps({
|
||||
eyebrow: String,
|
||||
title: String,
|
||||
subtitle: String,
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="page-hero">
|
||||
<div class="container">
|
||||
<span v-if="eyebrow" class="eyebrow">{{ eyebrow }}</span>
|
||||
<h1>{{ title }}</h1>
|
||||
<p v-if="subtitle" class="page-hero__sub">{{ subtitle }}</p>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.page-hero {
|
||||
padding: var(--space-9) 0 var(--space-7);
|
||||
border-bottom: 1px solid var(--color-border-soft);
|
||||
background:
|
||||
radial-gradient(800px 360px at 90% 0%, rgba(0, 229, 255, 0.08), transparent 60%);
|
||||
}
|
||||
.page-hero__sub {
|
||||
font-size: 1.15rem;
|
||||
color: var(--color-text-muted);
|
||||
max-width: 720px;
|
||||
margin: var(--space-4) 0 0;
|
||||
}
|
||||
</style>
|
||||
187
frontend/src/components/TheFooter.vue
Normal file
187
frontend/src/components/TheFooter.vue
Normal file
@@ -0,0 +1,187 @@
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { api } from '@/api/client'
|
||||
|
||||
const email = ref('')
|
||||
const status = ref('idle') // idle | loading | success | error
|
||||
const message = ref('')
|
||||
|
||||
async function subscribe() {
|
||||
if (!email.value) return
|
||||
status.value = 'loading'
|
||||
try {
|
||||
await api.subscribeNewsletter(email.value, 'footer')
|
||||
status.value = 'success'
|
||||
message.value = "You're on the list."
|
||||
email.value = ''
|
||||
} catch (err) {
|
||||
status.value = 'error'
|
||||
message.value = 'Something went wrong. Try again in a moment.'
|
||||
}
|
||||
}
|
||||
|
||||
const year = new Date().getFullYear()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<footer class="footer">
|
||||
<div class="container footer__grid">
|
||||
<div class="footer__brand">
|
||||
<div class="brand-line">
|
||||
<svg width="28" height="28" viewBox="0 0 64 64" aria-hidden="true">
|
||||
<defs>
|
||||
<linearGradient id="fg" x1="0" y1="0" x2="1" y2="1">
|
||||
<stop offset="0%" stop-color="#0B1437"/>
|
||||
<stop offset="100%" stop-color="#00E5FF"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<rect width="64" height="64" rx="14" fill="url(#fg)"/>
|
||||
<path d="M16 44 L26 28 L36 38 L48 18" stroke="#F4F6FB" stroke-width="4" fill="none" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
<strong>RisingCompute</strong>
|
||||
</div>
|
||||
<p class="footer__tagline">Accelerating the compute — IP cores for AI, space, and robotics.</p>
|
||||
<p class="footer__incub mono">Incubated at STIIC · IIST</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h4>Company</h4>
|
||||
<ul>
|
||||
<li><RouterLink to="/about">About</RouterLink></li>
|
||||
<li><RouterLink to="/careers">Careers</RouterLink></li>
|
||||
<li><RouterLink to="/blog">Insights</RouterLink></li>
|
||||
<li><RouterLink to="/contact">Contact</RouterLink></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h4>Products</h4>
|
||||
<ul>
|
||||
<li><RouterLink to="/products/ai-inference-ip">AI Inference IP</RouterLink></li>
|
||||
<li><RouterLink to="/products/cybersecurity-ip">Cybersecurity IP</RouterLink></li>
|
||||
<li><RouterLink to="/products/communication-ip">Communication IP</RouterLink></li>
|
||||
<li><RouterLink to="/technology">Technology</RouterLink></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="footer__news">
|
||||
<h4>Newsletter</h4>
|
||||
<p class="dim">Quarterly technical updates. No spam.</p>
|
||||
<form class="footer__sub" @submit.prevent="subscribe">
|
||||
<input
|
||||
v-model="email"
|
||||
type="email"
|
||||
required
|
||||
placeholder="you@company.com"
|
||||
aria-label="Email address"
|
||||
/>
|
||||
<button type="submit" class="btn btn--primary" :disabled="status === 'loading'">
|
||||
{{ status === 'loading' ? '…' : 'Subscribe' }}
|
||||
</button>
|
||||
</form>
|
||||
<p v-if="status === 'success'" class="footer__msg footer__msg--ok">{{ message }}</p>
|
||||
<p v-if="status === 'error'" class="footer__msg footer__msg--err">{{ message }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container footer__bottom">
|
||||
<p class="dim">© {{ year }} RisingCompute Pvt Ltd · Surat, Gujarat, India</p>
|
||||
<p class="dim">
|
||||
<RouterLink to="/contact">Privacy</RouterLink> ·
|
||||
<RouterLink to="/contact">Terms</RouterLink> ·
|
||||
<a href="mailto:contact@risingcompute.in">contact@risingcompute.in</a>
|
||||
</p>
|
||||
</div>
|
||||
</footer>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.footer {
|
||||
border-top: 1px solid var(--color-border-soft);
|
||||
padding: var(--space-8) 0 var(--space-5);
|
||||
background: linear-gradient(180deg, transparent, rgba(0, 0, 0, 0.25));
|
||||
margin-top: var(--space-9);
|
||||
}
|
||||
|
||||
.footer__grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1.6fr 1fr 1fr 1.4fr;
|
||||
gap: var(--space-7);
|
||||
margin-bottom: var(--space-7);
|
||||
}
|
||||
@media (max-width: 900px) {
|
||||
.footer__grid { grid-template-columns: 1fr 1fr; }
|
||||
}
|
||||
@media (max-width: 540px) {
|
||||
.footer__grid { grid-template-columns: 1fr; }
|
||||
}
|
||||
|
||||
.brand-line {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: var(--space-3);
|
||||
margin-bottom: var(--space-3);
|
||||
color: var(--color-text);
|
||||
}
|
||||
.footer__tagline { color: var(--color-text-muted); max-width: 280px; }
|
||||
.footer__incub { color: var(--color-text-dim); font-size: 0.75rem; letter-spacing: 0.08em; text-transform: uppercase; }
|
||||
|
||||
.footer h4 {
|
||||
font-size: 0.8rem;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.1em;
|
||||
text-transform: uppercase;
|
||||
color: var(--color-text-dim);
|
||||
margin-bottom: var(--space-4);
|
||||
}
|
||||
.footer ul {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
display: grid;
|
||||
gap: var(--space-2);
|
||||
}
|
||||
.footer ul a {
|
||||
color: var(--color-text-muted);
|
||||
font-size: 0.92rem;
|
||||
}
|
||||
.footer ul a:hover { color: var(--color-accent); }
|
||||
|
||||
.footer__sub {
|
||||
display: flex;
|
||||
gap: var(--space-2);
|
||||
margin-top: var(--space-3);
|
||||
}
|
||||
.footer__sub input {
|
||||
flex: 1;
|
||||
background: var(--color-bg-soft);
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-md);
|
||||
padding: 0.7rem 0.9rem;
|
||||
font-family: var(--font-sans);
|
||||
color: var(--color-text);
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
.footer__sub input:focus {
|
||||
outline: none;
|
||||
border-color: var(--color-accent);
|
||||
}
|
||||
.footer__sub button { padding: 0.7rem 1rem; font-size: 0.9rem; }
|
||||
.footer__msg { font-size: 0.85rem; margin-top: var(--space-2); }
|
||||
.footer__msg--ok { color: var(--color-success); }
|
||||
.footer__msg--err { color: var(--color-error); }
|
||||
|
||||
.footer__bottom {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding-top: var(--space-5);
|
||||
border-top: 1px solid var(--color-border-soft);
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
@media (max-width: 640px) {
|
||||
.footer__bottom { flex-direction: column; gap: var(--space-2); }
|
||||
}
|
||||
.footer__bottom a { color: var(--color-text-muted); }
|
||||
.footer__bottom a:hover { color: var(--color-accent); }
|
||||
</style>
|
||||
160
frontend/src/components/TheHeader.vue
Normal file
160
frontend/src/components/TheHeader.vue
Normal file
@@ -0,0 +1,160 @@
|
||||
<script setup>
|
||||
import { ref, onMounted, onBeforeUnmount } from 'vue'
|
||||
import { RouterLink } from 'vue-router'
|
||||
|
||||
const scrolled = ref(false)
|
||||
const menuOpen = ref(false)
|
||||
|
||||
const onScroll = () => { scrolled.value = window.scrollY > 8 }
|
||||
|
||||
onMounted(() => {
|
||||
window.addEventListener('scroll', onScroll, { passive: true })
|
||||
onScroll()
|
||||
})
|
||||
onBeforeUnmount(() => window.removeEventListener('scroll', onScroll))
|
||||
|
||||
const closeMenu = () => { menuOpen.value = false }
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<header class="nav" :class="{ 'nav--scrolled': scrolled }">
|
||||
<div class="container nav__inner">
|
||||
<RouterLink to="/" class="brand" @click="closeMenu">
|
||||
<svg width="32" height="32" viewBox="0 0 64 64" aria-hidden="true">
|
||||
<defs>
|
||||
<linearGradient id="logoGrad" x1="0" y1="0" x2="1" y2="1">
|
||||
<stop offset="0%" stop-color="#0B1437"/>
|
||||
<stop offset="100%" stop-color="#00E5FF"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<rect width="64" height="64" rx="14" fill="url(#logoGrad)"/>
|
||||
<path d="M16 44 L26 28 L36 38 L48 18" stroke="#F4F6FB" stroke-width="4" fill="none" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
<span class="brand__name">RisingCompute</span>
|
||||
</RouterLink>
|
||||
|
||||
<button
|
||||
class="nav__toggle"
|
||||
:aria-expanded="menuOpen"
|
||||
aria-label="Toggle menu"
|
||||
@click="menuOpen = !menuOpen"
|
||||
>
|
||||
<span></span><span></span><span></span>
|
||||
</button>
|
||||
|
||||
<nav class="nav__links" :class="{ 'nav__links--open': menuOpen }" @click="closeMenu">
|
||||
<RouterLink to="/products">Products</RouterLink>
|
||||
<RouterLink to="/technology">Technology</RouterLink>
|
||||
<RouterLink to="/about">About</RouterLink>
|
||||
<RouterLink to="/careers">Careers</RouterLink>
|
||||
<RouterLink to="/blog">Insights</RouterLink>
|
||||
<RouterLink to="/contact" class="btn btn--primary nav__cta">Talk to us</RouterLink>
|
||||
</nav>
|
||||
</div>
|
||||
</header>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.nav {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: var(--nav-height);
|
||||
z-index: 50;
|
||||
background: rgba(11, 20, 55, 0.6);
|
||||
backdrop-filter: saturate(1.4) blur(14px);
|
||||
-webkit-backdrop-filter: saturate(1.4) blur(14px);
|
||||
border-bottom: 1px solid transparent;
|
||||
transition: background var(--transition), border-color var(--transition);
|
||||
}
|
||||
.nav--scrolled {
|
||||
background: rgba(11, 20, 55, 0.88);
|
||||
border-bottom-color: var(--color-border-soft);
|
||||
}
|
||||
|
||||
.nav__inner {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: var(--space-5);
|
||||
}
|
||||
|
||||
.brand {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: var(--space-3);
|
||||
color: var(--color-text);
|
||||
font-weight: 600;
|
||||
letter-spacing: -0.01em;
|
||||
}
|
||||
.brand:hover { color: var(--color-text); }
|
||||
.brand__name { font-size: 1.05rem; }
|
||||
|
||||
.nav__links {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-5);
|
||||
}
|
||||
.nav__links :where(a):not(.btn) {
|
||||
color: var(--color-text-muted);
|
||||
font-size: 0.95rem;
|
||||
font-weight: 500;
|
||||
padding: 0.4rem 0;
|
||||
border-bottom: 2px solid transparent;
|
||||
}
|
||||
.nav__links :where(a):not(.btn):hover {
|
||||
color: var(--color-text);
|
||||
}
|
||||
.nav__links :where(a.router-link-active):not(.btn) {
|
||||
color: var(--color-accent);
|
||||
border-bottom-color: var(--color-accent);
|
||||
}
|
||||
.nav__cta { padding: 0.55rem 1rem; font-size: 0.9rem; }
|
||||
|
||||
.nav__toggle {
|
||||
display: none;
|
||||
background: transparent;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-sm);
|
||||
width: 40px;
|
||||
height: 36px;
|
||||
padding: 8px 10px;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
cursor: pointer;
|
||||
}
|
||||
.nav__toggle span {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 2px;
|
||||
background: var(--color-text);
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
@media (max-width: 880px) {
|
||||
.nav__toggle { display: flex; }
|
||||
.nav__links {
|
||||
position: absolute;
|
||||
top: var(--nav-height);
|
||||
left: 0;
|
||||
right: 0;
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
padding: var(--space-5);
|
||||
background: rgba(11, 20, 55, 0.98);
|
||||
border-bottom: 1px solid var(--color-border-soft);
|
||||
transform: translateY(-12px);
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
transition: all var(--transition);
|
||||
}
|
||||
.nav__links--open {
|
||||
transform: translateY(0);
|
||||
opacity: 1;
|
||||
pointer-events: auto;
|
||||
}
|
||||
.nav__cta { margin-top: var(--space-2); }
|
||||
}
|
||||
</style>
|
||||
6
frontend/src/main.js
Normal file
6
frontend/src/main.js
Normal file
@@ -0,0 +1,6 @@
|
||||
import { createApp } from 'vue'
|
||||
import App from './App.vue'
|
||||
import router from './router'
|
||||
import './assets/styles/main.css'
|
||||
|
||||
createApp(App).use(router).mount('#app')
|
||||
30
frontend/src/router/index.js
Normal file
30
frontend/src/router/index.js
Normal file
@@ -0,0 +1,30 @@
|
||||
import { createRouter, createWebHistory } from 'vue-router'
|
||||
|
||||
const routes = [
|
||||
{ path: '/', name: 'home', component: () => import('@/views/HomeView.vue'), meta: { title: 'RisingCompute — Accelerating the compute' } },
|
||||
{ path: '/about', name: 'about', component: () => import('@/views/AboutView.vue'), meta: { title: 'About — RisingCompute' } },
|
||||
{ path: '/products', name: 'products', component: () => import('@/views/ProductsView.vue'), meta: { title: 'Products — RisingCompute' } },
|
||||
{ path: '/products/:slug', name: 'product-detail', component: () => import('@/views/ProductDetailView.vue'), meta: { title: 'Product — RisingCompute' } },
|
||||
{ path: '/technology', name: 'technology', component: () => import('@/views/TechnologyView.vue'), meta: { title: 'Technology — RisingCompute' } },
|
||||
{ path: '/careers', name: 'careers', component: () => import('@/views/CareersView.vue'), meta: { title: 'Careers — RisingCompute' } },
|
||||
{ path: '/blog', name: 'blog', component: () => import('@/views/BlogView.vue'), meta: { title: 'Insights — RisingCompute' } },
|
||||
{ path: '/blog/:slug', name: 'blog-post', component: () => import('@/views/BlogPostView.vue'), meta: { title: 'Insights — RisingCompute' } },
|
||||
{ path: '/contact', name: 'contact', component: () => import('@/views/ContactView.vue'), meta: { title: 'Talk to us — RisingCompute' } },
|
||||
{ path: '/:pathMatch(.*)*', name: 'not-found', component: () => import('@/views/NotFoundView.vue'), meta: { title: 'Not found — RisingCompute' } },
|
||||
]
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHistory(),
|
||||
routes,
|
||||
scrollBehavior(to, from, saved) {
|
||||
if (saved) return saved
|
||||
if (to.hash) return { el: to.hash, behavior: 'smooth' }
|
||||
return { top: 0 }
|
||||
},
|
||||
})
|
||||
|
||||
router.afterEach((to) => {
|
||||
if (to.meta?.title) document.title = to.meta.title
|
||||
})
|
||||
|
||||
export default router
|
||||
159
frontend/src/views/AboutView.vue
Normal file
159
frontend/src/views/AboutView.vue
Normal file
@@ -0,0 +1,159 @@
|
||||
<script setup>
|
||||
import { onMounted, ref } from 'vue'
|
||||
import { RouterLink } from 'vue-router'
|
||||
import { api } from '@/api/client'
|
||||
import SectionHero from '@/components/SectionHero.vue'
|
||||
import FounderCard from '@/components/FounderCard.vue'
|
||||
|
||||
const founders = ref([])
|
||||
const loading = ref(true)
|
||||
|
||||
onMounted(async () => {
|
||||
try { founders.value = await api.listFounders() }
|
||||
catch (e) {}
|
||||
finally { loading.value = false }
|
||||
})
|
||||
|
||||
const values = [
|
||||
{ name: 'Fast', body: 'We measure things. We ship blocks. We don\'t hide behind roadmaps.' },
|
||||
{ name: 'Reliable', body: 'Verification-first. Documentation that an integrator can actually use.' },
|
||||
{ name: 'Robust', body: 'Designed for orbits and factory floors — robustness is the baseline, not a feature.' },
|
||||
]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<SectionHero
|
||||
eyebrow="About"
|
||||
title="Built by a satellite-software team, for everyone who needs that compute."
|
||||
subtitle="RisingCompute designs parallel hardware architectures and IP cores for AI, space, and robotics. The founders met in the SSPACE lab at IIST — and brought the same standards out into the open."
|
||||
/>
|
||||
|
||||
<!-- STORY -->
|
||||
<section class="section section--tight">
|
||||
<div class="container story">
|
||||
<div>
|
||||
<span class="eyebrow">Our story</span>
|
||||
<h2>Closing the compute gap.</h2>
|
||||
</div>
|
||||
<div class="story__body">
|
||||
<p>
|
||||
RisingCompute began in 2026 inside the SSPACE lab at IIST, where our founding
|
||||
team spent two years building computation systems for satellites — IP that has
|
||||
since flown in space.
|
||||
</p>
|
||||
<p>
|
||||
Working at that level taught us something simple: the difference between what a
|
||||
research team can do with AI and what most engineers and companies can do comes
|
||||
down to the compute they have access to. We started RisingCompute to close that
|
||||
gap. By building parallel hardware architectures and reusable IP cores, we make
|
||||
accelerated compute scalable and easy to integrate — so an aerospace OEM, a
|
||||
robotics startup, or a defense electronics lab can get research-grade
|
||||
performance without rebuilding the stack from scratch.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<hr class="divider container" />
|
||||
|
||||
<!-- FOUNDERS -->
|
||||
<section class="section section--tight">
|
||||
<div class="container">
|
||||
<div class="section-head">
|
||||
<span class="eyebrow">Founders</span>
|
||||
<h2>Three engineers. One full stack.</h2>
|
||||
<p class="muted">
|
||||
Every founder owns a clear technical domain. Together we cover system architecture
|
||||
down to silicon.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div v-if="loading" class="dim mono">Loading…</div>
|
||||
<div v-else class="grid grid--3">
|
||||
<FounderCard v-for="f in founders" :key="f.name" :founder="f" />
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<hr class="divider container" />
|
||||
|
||||
<!-- VALUES -->
|
||||
<section class="section section--tight">
|
||||
<div class="container">
|
||||
<div class="section-head">
|
||||
<span class="eyebrow">Core values</span>
|
||||
<h2>Fast. Reliable. Robust.</h2>
|
||||
</div>
|
||||
<div class="grid grid--3">
|
||||
<div v-for="v in values" :key="v.name" class="value-card">
|
||||
<h3>{{ v.name }}</h3>
|
||||
<p>{{ v.body }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- FACTS -->
|
||||
<section class="section section--tight">
|
||||
<div class="container facts">
|
||||
<div>
|
||||
<span class="eyebrow">Where we are</span>
|
||||
<h3 class="facts__h">Surat, Gujarat</h3>
|
||||
<p class="muted">Primary office and engineering team.</p>
|
||||
</div>
|
||||
<div>
|
||||
<span class="eyebrow">Where we're incubated</span>
|
||||
<h3 class="facts__h">STIIC · IIST</h3>
|
||||
<p class="muted">Space Technology Incubation & Innovation Cell, IIST.</p>
|
||||
</div>
|
||||
<div>
|
||||
<span class="eyebrow">Stage</span>
|
||||
<h3 class="facts__h">Pre-revenue</h3>
|
||||
<p class="muted">Founded 2026. Three IP cores in customer-ready testing.</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- CTA -->
|
||||
<section class="section text-center">
|
||||
<div class="container">
|
||||
<h2>Work with us.</h2>
|
||||
<p class="muted">Talk to the founders directly — engineering-first conversations only.</p>
|
||||
<RouterLink to="/contact" class="btn btn--primary">Talk to us</RouterLink>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.story {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1.6fr;
|
||||
gap: var(--space-7);
|
||||
}
|
||||
@media (max-width: 860px) { .story { grid-template-columns: 1fr; } }
|
||||
.story__body p { font-size: 1.05rem; }
|
||||
|
||||
.section-head { margin-bottom: var(--space-6); max-width: 720px; }
|
||||
|
||||
.value-card {
|
||||
background: linear-gradient(180deg, var(--color-surface), var(--color-surface-2));
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: var(--space-6);
|
||||
}
|
||||
.value-card h3 {
|
||||
font-family: var(--font-mono);
|
||||
color: var(--color-accent);
|
||||
margin-bottom: var(--space-3);
|
||||
font-size: 1.1rem;
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
|
||||
.facts {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: var(--space-6);
|
||||
}
|
||||
@media (max-width: 860px) { .facts { grid-template-columns: 1fr; } }
|
||||
.facts__h { margin: var(--space-3) 0 var(--space-2); }
|
||||
</style>
|
||||
108
frontend/src/views/BlogPostView.vue
Normal file
108
frontend/src/views/BlogPostView.vue
Normal file
@@ -0,0 +1,108 @@
|
||||
<script setup>
|
||||
import { onMounted, ref, watch } from 'vue'
|
||||
import { useRoute, RouterLink } from 'vue-router'
|
||||
import { api } from '@/api/client'
|
||||
|
||||
const route = useRoute()
|
||||
const post = ref(null)
|
||||
const loading = ref(true)
|
||||
const notFound = ref(false)
|
||||
|
||||
async function load(slug) {
|
||||
loading.value = true
|
||||
notFound.value = false
|
||||
try {
|
||||
post.value = await api.getPost(slug)
|
||||
if (post.value?.title) document.title = `${post.value.title} — RisingCompute`
|
||||
} catch (e) {
|
||||
notFound.value = true
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => load(route.params.slug))
|
||||
watch(() => route.params.slug, (s) => s && load(s))
|
||||
|
||||
function fmtDate(iso) {
|
||||
try { return new Date(iso).toLocaleDateString('en-IN', { year: 'numeric', month: 'short', day: 'numeric' }) }
|
||||
catch { return iso }
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-if="loading" class="container section dim mono">Loading…</div>
|
||||
|
||||
<section v-else-if="notFound" class="section text-center">
|
||||
<div class="container">
|
||||
<h1>Post not found.</h1>
|
||||
<RouterLink to="/blog" class="btn btn--ghost">Back to insights</RouterLink>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<article v-else class="post-page">
|
||||
<header class="post-page__head">
|
||||
<div class="container">
|
||||
<RouterLink to="/blog" class="back-link">← All insights</RouterLink>
|
||||
<span class="pill">{{ post.category_label }}</span>
|
||||
<h1>{{ post.title }}</h1>
|
||||
<p class="dim mono post-page__meta">
|
||||
{{ post.author_name }} · {{ fmtDate(post.published_at) }} · {{ post.read_time_minutes }} min read
|
||||
</p>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="container post-page__body">
|
||||
<p class="post-page__excerpt">{{ post.excerpt }}</p>
|
||||
<!-- Body is markdown-ish; for v1 we render as preformatted text with double-newline paragraphing -->
|
||||
<div class="prose" v-for="(para, idx) in post.body.split(/\n\n+/)" :key="idx">
|
||||
<h2 v-if="para.startsWith('## ')">{{ para.replace(/^##\s*/, '') }}</h2>
|
||||
<p v-else>{{ para }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container post-page__footer">
|
||||
<RouterLink to="/blog" class="btn btn--ghost">← More insights</RouterLink>
|
||||
<RouterLink to="/contact" class="btn btn--primary">Talk to us</RouterLink>
|
||||
</div>
|
||||
</article>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.back-link { color: var(--color-text-dim); font-size: 0.9rem; }
|
||||
.back-link:hover { color: var(--color-accent); }
|
||||
|
||||
.post-page__head {
|
||||
padding: var(--space-8) 0 var(--space-5);
|
||||
border-bottom: 1px solid var(--color-border-soft);
|
||||
background: radial-gradient(800px 360px at 90% 0%, rgba(0, 229, 255, 0.08), transparent 60%);
|
||||
}
|
||||
.post-page__head h1 { margin-top: var(--space-3); max-width: 820px; }
|
||||
.post-page__meta { margin-top: var(--space-2); }
|
||||
|
||||
.post-page__body {
|
||||
max-width: 760px;
|
||||
padding: var(--space-7) var(--space-5);
|
||||
}
|
||||
.post-page__excerpt {
|
||||
font-size: 1.2rem;
|
||||
color: var(--color-text);
|
||||
border-left: 2px solid var(--color-accent);
|
||||
padding-left: var(--space-4);
|
||||
margin-bottom: var(--space-6);
|
||||
}
|
||||
.prose h2 { margin-top: var(--space-6); }
|
||||
.prose p { font-size: 1.05rem; }
|
||||
|
||||
.post-page__footer {
|
||||
max-width: 760px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: var(--space-5);
|
||||
border-top: 1px solid var(--color-border-soft);
|
||||
margin-top: var(--space-6);
|
||||
gap: var(--space-4);
|
||||
}
|
||||
@media (max-width: 540px) { .post-page__footer { flex-direction: column-reverse; } }
|
||||
</style>
|
||||
123
frontend/src/views/BlogView.vue
Normal file
123
frontend/src/views/BlogView.vue
Normal file
@@ -0,0 +1,123 @@
|
||||
<script setup>
|
||||
import { computed, onMounted, ref } from 'vue'
|
||||
import { RouterLink } from 'vue-router'
|
||||
import { api } from '@/api/client'
|
||||
import SectionHero from '@/components/SectionHero.vue'
|
||||
|
||||
const posts = ref([])
|
||||
const loading = ref(true)
|
||||
const activeCategory = ref('all')
|
||||
|
||||
onMounted(async () => {
|
||||
try { posts.value = await api.listPosts() }
|
||||
catch (e) {}
|
||||
finally { loading.value = false }
|
||||
})
|
||||
|
||||
const categories = computed(() => {
|
||||
const set = new Map()
|
||||
set.set('all', 'All')
|
||||
for (const p of posts.value) set.set(p.category, p.category_label)
|
||||
return Array.from(set, ([value, label]) => ({ value, label }))
|
||||
})
|
||||
|
||||
const filtered = computed(() =>
|
||||
activeCategory.value === 'all'
|
||||
? posts.value
|
||||
: posts.value.filter(p => p.category === activeCategory.value)
|
||||
)
|
||||
|
||||
function fmtDate(iso) {
|
||||
try { return new Date(iso).toLocaleDateString('en-IN', { year: 'numeric', month: 'short', day: 'numeric' }) }
|
||||
catch { return iso }
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<SectionHero
|
||||
eyebrow="Insights"
|
||||
title="Notes from the lab."
|
||||
subtitle="Engineering notes, architecture choices, and the occasional founder essay. Written by the team — not a content desk."
|
||||
/>
|
||||
|
||||
<section class="section">
|
||||
<div class="container">
|
||||
<div class="filters" v-if="categories.length > 1">
|
||||
<button
|
||||
v-for="c in categories"
|
||||
:key="c.value"
|
||||
class="filter"
|
||||
:class="{ 'filter--active': activeCategory === c.value }"
|
||||
@click="activeCategory = c.value"
|
||||
>
|
||||
{{ c.label }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div v-if="loading" class="dim mono">Loading…</div>
|
||||
<div v-else class="grid grid--2 posts">
|
||||
<RouterLink
|
||||
v-for="post in filtered"
|
||||
:key="post.slug"
|
||||
:to="`/blog/${post.slug}`"
|
||||
class="post"
|
||||
>
|
||||
<div class="post__head">
|
||||
<span class="pill">{{ post.category_label }}</span>
|
||||
<span class="dim mono">{{ post.read_time_minutes }} min</span>
|
||||
</div>
|
||||
<h3>{{ post.title }}</h3>
|
||||
<p class="muted">{{ post.excerpt }}</p>
|
||||
<span class="dim mono">{{ post.author_name }} · {{ fmtDate(post.published_at) }}</span>
|
||||
</RouterLink>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.filters {
|
||||
display: flex;
|
||||
gap: var(--space-2);
|
||||
flex-wrap: wrap;
|
||||
margin-bottom: var(--space-6);
|
||||
}
|
||||
.filter {
|
||||
background: transparent;
|
||||
border: 1px solid var(--color-border);
|
||||
color: var(--color-text-muted);
|
||||
border-radius: 999px;
|
||||
padding: 0.4rem 0.9rem;
|
||||
font-family: var(--font-sans);
|
||||
font-size: 0.85rem;
|
||||
cursor: pointer;
|
||||
transition: all var(--transition-fast);
|
||||
}
|
||||
.filter:hover { border-color: var(--color-accent); color: var(--color-accent); }
|
||||
.filter--active {
|
||||
background: var(--color-accent-soft);
|
||||
border-color: var(--color-accent);
|
||||
color: var(--color-accent);
|
||||
}
|
||||
|
||||
.posts { gap: var(--space-5); }
|
||||
.post {
|
||||
background: linear-gradient(180deg, var(--color-surface), var(--color-surface-2));
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: var(--space-6);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-3);
|
||||
color: var(--color-text);
|
||||
transition: border-color var(--transition), transform var(--transition);
|
||||
}
|
||||
.post:hover {
|
||||
border-color: rgba(0, 229, 255, 0.4);
|
||||
transform: translateY(-3px);
|
||||
color: var(--color-text);
|
||||
}
|
||||
.post__head { display: flex; justify-content: space-between; align-items: center; }
|
||||
.post h3 { margin: 0; font-size: 1.3rem; }
|
||||
.post p { margin: 0; flex: 1; }
|
||||
</style>
|
||||
141
frontend/src/views/CareersView.vue
Normal file
141
frontend/src/views/CareersView.vue
Normal file
@@ -0,0 +1,141 @@
|
||||
<script setup>
|
||||
import { onMounted, ref } from 'vue'
|
||||
import { RouterLink } from 'vue-router'
|
||||
import { api } from '@/api/client'
|
||||
import SectionHero from '@/components/SectionHero.vue'
|
||||
|
||||
const jobs = ref([])
|
||||
const loading = ref(true)
|
||||
|
||||
onMounted(async () => {
|
||||
try { jobs.value = await api.listJobs() }
|
||||
catch (e) {}
|
||||
finally { loading.value = false }
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<SectionHero
|
||||
eyebrow="Careers"
|
||||
title="Build silicon that flies."
|
||||
subtitle="We're a small founding team in Surat and at IIST. The bar is high; so is the autonomy. If you want to own real RTL, real verification, and real customer relationships from day one, we should talk."
|
||||
/>
|
||||
|
||||
<section class="section section--tight">
|
||||
<div class="container">
|
||||
<div class="why-grid">
|
||||
<div>
|
||||
<h3 class="mono mono-head">Why us</h3>
|
||||
<ul class="reasons">
|
||||
<li>Founder-led engineering. You sit next to the people who decide what to build.</li>
|
||||
<li>Real flight-heritage work — variants of our IP have flown.</li>
|
||||
<li>Ownership over a block, not a sliver.</li>
|
||||
<li>Equity for the first ten people.</li>
|
||||
<li>Surat HQ + IIST presence — both real labs.</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="mono mono-head">How we hire</h3>
|
||||
<ol class="steps">
|
||||
<li><strong>Intro chat</strong> (30 min) — what you've shipped, what you want next.</li>
|
||||
<li><strong>Technical deep-dive</strong> (90 min) — a real problem from our stack.</li>
|
||||
<li><strong>Founder round</strong> — values, autonomy, expectations.</li>
|
||||
<li><strong>Offer</strong> within a week.</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<hr class="divider container" />
|
||||
|
||||
<section class="section section--tight">
|
||||
<div class="container">
|
||||
<span class="eyebrow">Open roles</span>
|
||||
<h2>What we're hiring for.</h2>
|
||||
|
||||
<div v-if="loading" class="dim mono">Loading…</div>
|
||||
<div v-else-if="!jobs.length" class="empty">
|
||||
<p class="muted">
|
||||
No open roles posted right now. We always want to hear from VLSI, RTL,
|
||||
verification, and DSP engineers — send us a note.
|
||||
</p>
|
||||
<RouterLink :to="{ path: '/contact', query: { interest: 'careers' } }" class="btn btn--primary">
|
||||
Introduce yourself
|
||||
</RouterLink>
|
||||
</div>
|
||||
<div v-else class="jobs">
|
||||
<article v-for="j in jobs" :key="j.slug" class="job">
|
||||
<div>
|
||||
<h3>{{ j.title }}</h3>
|
||||
<p class="dim mono job__meta">{{ j.location_label }} · {{ j.employment_type }} · posted {{ j.posted_at }}</p>
|
||||
</div>
|
||||
<RouterLink :to="{ path: '/contact', query: { interest: 'careers' } }" class="btn btn--ghost">
|
||||
Apply →
|
||||
</RouterLink>
|
||||
</article>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.why-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: var(--space-7);
|
||||
}
|
||||
@media (max-width: 760px) { .why-grid { grid-template-columns: 1fr; } }
|
||||
.mono-head {
|
||||
color: var(--color-text-dim);
|
||||
font-size: 0.78rem;
|
||||
letter-spacing: 0.1em;
|
||||
text-transform: uppercase;
|
||||
margin-bottom: var(--space-4);
|
||||
}
|
||||
.reasons, .steps {
|
||||
display: grid;
|
||||
gap: var(--space-3);
|
||||
color: var(--color-text-muted);
|
||||
}
|
||||
.reasons { list-style: none; padding: 0; }
|
||||
.reasons li { padding-left: var(--space-5); position: relative; }
|
||||
.reasons li::before {
|
||||
content: '+';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
color: var(--color-accent);
|
||||
font-family: var(--font-mono);
|
||||
font-weight: 600;
|
||||
}
|
||||
.steps { padding-left: var(--space-5); }
|
||||
.steps li::marker { color: var(--color-accent); font-family: var(--font-mono); }
|
||||
|
||||
.jobs {
|
||||
display: grid;
|
||||
gap: var(--space-3);
|
||||
margin-top: var(--space-5);
|
||||
}
|
||||
.job {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: var(--space-4);
|
||||
background: var(--color-surface);
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-md);
|
||||
padding: var(--space-5);
|
||||
}
|
||||
.job h3 { margin: 0 0 var(--space-1); font-size: 1.15rem; }
|
||||
.job__meta { margin: 0; font-size: 0.8rem; }
|
||||
|
||||
.empty {
|
||||
background: var(--color-surface);
|
||||
border: 1px dashed var(--color-border);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: var(--space-6);
|
||||
text-align: center;
|
||||
margin-top: var(--space-5);
|
||||
}
|
||||
.empty p { margin: 0 0 var(--space-4); }
|
||||
</style>
|
||||
89
frontend/src/views/ContactView.vue
Normal file
89
frontend/src/views/ContactView.vue
Normal file
@@ -0,0 +1,89 @@
|
||||
<script setup>
|
||||
import { useRoute } from 'vue-router'
|
||||
import SectionHero from '@/components/SectionHero.vue'
|
||||
import ContactForm from '@/components/ContactForm.vue'
|
||||
|
||||
const route = useRoute()
|
||||
const defaultInterest = String(route.query.interest || 'other')
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<SectionHero
|
||||
eyebrow="Talk to us"
|
||||
title="Start an evaluation."
|
||||
subtitle="Conversations land with an engineer, not a sales rep. One business-day reply."
|
||||
/>
|
||||
|
||||
<section class="section">
|
||||
<div class="container contact-grid">
|
||||
<div class="contact-info">
|
||||
<h3>Direct lines</h3>
|
||||
<ul>
|
||||
<li>
|
||||
<span class="dim mono">Email</span>
|
||||
<a href="mailto:contact@risingcompute.in">contact@risingcompute.in</a>
|
||||
</li>
|
||||
<li>
|
||||
<span class="dim mono">HQ</span>
|
||||
<p>Surat, Gujarat, India</p>
|
||||
</li>
|
||||
<li>
|
||||
<span class="dim mono">Incubation</span>
|
||||
<p>STIIC · IIST, Thiruvananthapuram</p>
|
||||
</li>
|
||||
<li>
|
||||
<span class="dim mono">Hours</span>
|
||||
<p>Mon–Fri · 09:30–18:30 IST</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<hr class="divider" />
|
||||
|
||||
<h3>What to expect</h3>
|
||||
<ol class="steps">
|
||||
<li>A short reply from a founder within one business day.</li>
|
||||
<li>A 30-minute qualification call.</li>
|
||||
<li>Datasheet + reference design under NDA.</li>
|
||||
<li>Evaluation licence terms.</li>
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<ContactForm :default-interest="defaultInterest" />
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.contact-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1.4fr;
|
||||
gap: var(--space-7);
|
||||
}
|
||||
@media (max-width: 900px) { .contact-grid { grid-template-columns: 1fr; } }
|
||||
|
||||
.contact-info ul {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0 0 var(--space-5);
|
||||
display: grid;
|
||||
gap: var(--space-4);
|
||||
}
|
||||
.contact-info li { display: grid; gap: var(--space-1); }
|
||||
.contact-info li span.mono {
|
||||
font-size: 0.72rem;
|
||||
letter-spacing: 0.1em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
.contact-info li p { margin: 0; }
|
||||
.contact-info a { font-size: 1.05rem; }
|
||||
|
||||
.steps {
|
||||
padding-left: var(--space-5);
|
||||
display: grid;
|
||||
gap: var(--space-2);
|
||||
color: var(--color-text-muted);
|
||||
}
|
||||
.steps li::marker { color: var(--color-accent); font-family: var(--font-mono); }
|
||||
</style>
|
||||
314
frontend/src/views/HomeView.vue
Normal file
314
frontend/src/views/HomeView.vue
Normal file
@@ -0,0 +1,314 @@
|
||||
<script setup>
|
||||
import { onMounted, ref } from 'vue'
|
||||
import { RouterLink } from 'vue-router'
|
||||
import { api } from '@/api/client'
|
||||
import ProductCard from '@/components/ProductCard.vue'
|
||||
|
||||
const products = ref([])
|
||||
const posts = ref([])
|
||||
const loading = ref(true)
|
||||
|
||||
onMounted(async () => {
|
||||
try {
|
||||
const [p, b] = await Promise.all([api.listProducts(), api.listPosts()])
|
||||
products.value = p
|
||||
posts.value = b.slice(0, 3)
|
||||
} catch (e) { /* surface a friendlier UI in production */ }
|
||||
finally { loading.value = false }
|
||||
})
|
||||
|
||||
const values = [
|
||||
{ name: 'Fast', body: 'Parallel architectures, deterministic latency, throughput-per-watt that ships.' },
|
||||
{ name: 'Reliable', body: 'Verification-first design. Heritage you can audit, not heritage you have to take on faith.' },
|
||||
{ name: 'Robust', body: 'Built for orbits, factory floors, and defense supply chains — not a controlled bench.' },
|
||||
]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<!-- HERO -->
|
||||
<section class="hero">
|
||||
<div class="container hero__inner">
|
||||
<div class="hero__copy">
|
||||
<span class="eyebrow">Semiconductor IP · India · Flight-heritage</span>
|
||||
<h1>Accelerating the compute.</h1>
|
||||
<p class="hero__sub">
|
||||
Parallel hardware architectures and IP cores for <strong>AI</strong>, <strong>space</strong>,
|
||||
and <strong>robotics</strong>. Designed in India, flown in orbit.
|
||||
</p>
|
||||
<div class="hero__cta">
|
||||
<RouterLink to="/contact" class="btn btn--primary">Talk to us</RouterLink>
|
||||
<RouterLink to="/technology" class="btn btn--ghost">Read the architecture brief →</RouterLink>
|
||||
</div>
|
||||
<div class="hero__proof">
|
||||
<span class="pill">IIST · STIIC</span>
|
||||
<span class="pill">Flight-heritage IP</span>
|
||||
<span class="pill">Founded 2026</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Decorative compute visual -->
|
||||
<div class="hero__visual" aria-hidden="true">
|
||||
<svg viewBox="0 0 420 420" xmlns="http://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<linearGradient id="chipGrad" x1="0" y1="0" x2="1" y2="1">
|
||||
<stop offset="0%" stop-color="#00E5FF" stop-opacity="0.55"/>
|
||||
<stop offset="100%" stop-color="#0B1437" stop-opacity="0"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="lineGrad" x1="0" y1="0" x2="1" y2="0">
|
||||
<stop offset="0%" stop-color="#00E5FF" stop-opacity="0"/>
|
||||
<stop offset="50%" stop-color="#00E5FF" stop-opacity="0.7"/>
|
||||
<stop offset="100%" stop-color="#00E5FF" stop-opacity="0"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<!-- Outer ring -->
|
||||
<circle cx="210" cy="210" r="200" fill="none" stroke="#2A3463" stroke-width="1"/>
|
||||
<circle cx="210" cy="210" r="150" fill="none" stroke="#2A3463" stroke-width="1" stroke-dasharray="2 4"/>
|
||||
<!-- Chip square -->
|
||||
<rect x="130" y="130" width="160" height="160" rx="16" fill="url(#chipGrad)" stroke="#00E5FF" stroke-width="1.5" opacity="0.9"/>
|
||||
<!-- Pins -->
|
||||
<g stroke="#00E5FF" stroke-width="1.5" opacity="0.7">
|
||||
<line x1="50" y1="170" x2="130" y2="170"/>
|
||||
<line x1="50" y1="210" x2="130" y2="210"/>
|
||||
<line x1="50" y1="250" x2="130" y2="250"/>
|
||||
<line x1="290" y1="170" x2="370" y2="170"/>
|
||||
<line x1="290" y1="210" x2="370" y2="210"/>
|
||||
<line x1="290" y1="250" x2="370" y2="250"/>
|
||||
<line x1="170" y1="50" x2="170" y2="130"/>
|
||||
<line x1="210" y1="50" x2="210" y2="130"/>
|
||||
<line x1="250" y1="50" x2="250" y2="130"/>
|
||||
<line x1="170" y1="290" x2="170" y2="370"/>
|
||||
<line x1="210" y1="290" x2="210" y2="370"/>
|
||||
<line x1="250" y1="290" x2="250" y2="370"/>
|
||||
</g>
|
||||
<!-- Inner grid -->
|
||||
<g stroke="#00E5FF" stroke-width="0.6" opacity="0.5">
|
||||
<line x1="170" y1="150" x2="170" y2="270"/>
|
||||
<line x1="210" y1="150" x2="210" y2="270"/>
|
||||
<line x1="250" y1="150" x2="250" y2="270"/>
|
||||
<line x1="150" y1="170" x2="270" y2="170"/>
|
||||
<line x1="150" y1="210" x2="270" y2="210"/>
|
||||
<line x1="150" y1="250" x2="270" y2="250"/>
|
||||
</g>
|
||||
<!-- Animated traveling pulse -->
|
||||
<rect x="50" y="209" width="320" height="2" fill="url(#lineGrad)">
|
||||
<animate attributeName="x" from="-120" to="420" dur="3s" repeatCount="indefinite"/>
|
||||
</rect>
|
||||
<!-- Core text -->
|
||||
<text x="210" y="216" text-anchor="middle" fill="#F4F6FB" font-family="JetBrains Mono" font-size="14" letter-spacing="2">RC-01</text>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- VALUES -->
|
||||
<section class="section section--tight">
|
||||
<div class="container">
|
||||
<div class="values-grid">
|
||||
<div v-for="v in values" :key="v.name" class="value">
|
||||
<h3>{{ v.name }}.</h3>
|
||||
<p>{{ v.body }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- PRODUCTS -->
|
||||
<section class="section">
|
||||
<div class="container">
|
||||
<div class="section-head">
|
||||
<span class="eyebrow">What we ship</span>
|
||||
<h2>One vendor for AI, security, and comms IP.</h2>
|
||||
<p class="muted section-head__lead">
|
||||
Our IP catalogue covers the three blocks every modern payload, robot, and edge product
|
||||
ends up integrating — usually from three different vendors.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div v-if="loading" class="dim mono">Loading products…</div>
|
||||
<div v-else class="grid grid--3">
|
||||
<ProductCard v-for="p in products" :key="p.slug" :product="p" />
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- PROOF -->
|
||||
<section class="section proof">
|
||||
<div class="container proof__inner">
|
||||
<div>
|
||||
<span class="eyebrow">Flight heritage</span>
|
||||
<h2>Our IP has flown.<br/>Yours can too.</h2>
|
||||
<p class="muted">
|
||||
The founding team spent two years inside the SSPACE lab at IIST building computation
|
||||
systems for satellites. The IP that flew on those missions is the same IP we're
|
||||
productising for the open market.
|
||||
</p>
|
||||
<RouterLink to="/about" class="btn btn--ghost">Read our story →</RouterLink>
|
||||
</div>
|
||||
<div class="proof__stats">
|
||||
<div><strong>2+</strong><span>years in flight programmes</span></div>
|
||||
<div><strong>3</strong><span>IP cores in customer-ready testing</span></div>
|
||||
<div><strong>5</strong><span>engineers across system + RTL</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- BLOG -->
|
||||
<section class="section">
|
||||
<div class="container">
|
||||
<div class="section-head">
|
||||
<span class="eyebrow">Insights</span>
|
||||
<h2>Notes from the lab.</h2>
|
||||
</div>
|
||||
|
||||
<div v-if="loading" class="dim mono">Loading…</div>
|
||||
<div v-else class="grid grid--3">
|
||||
<RouterLink
|
||||
v-for="post in posts"
|
||||
:key="post.slug"
|
||||
:to="`/blog/${post.slug}`"
|
||||
class="post-card"
|
||||
>
|
||||
<span class="pill">{{ post.category_label }}</span>
|
||||
<h3>{{ post.title }}</h3>
|
||||
<p class="muted">{{ post.excerpt }}</p>
|
||||
<span class="mono dim">{{ post.author_name }} · {{ post.read_time_minutes }} min</span>
|
||||
</RouterLink>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- CTA -->
|
||||
<section class="section cta">
|
||||
<div class="container cta__inner">
|
||||
<h2>Start an evaluation.</h2>
|
||||
<p class="muted">One business-day reply. Conversations land with an engineer, not a sales rep.</p>
|
||||
<RouterLink to="/contact" class="btn btn--primary">Talk to us</RouterLink>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
/* ---------- Hero ---------- */
|
||||
.hero {
|
||||
padding: var(--space-9) 0 var(--space-8);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
.hero__inner {
|
||||
display: grid;
|
||||
grid-template-columns: 1.15fr 1fr;
|
||||
gap: var(--space-7);
|
||||
align-items: center;
|
||||
}
|
||||
@media (max-width: 980px) {
|
||||
.hero__inner { grid-template-columns: 1fr; }
|
||||
.hero__visual { order: -1; max-width: 380px; margin: 0 auto; }
|
||||
}
|
||||
.hero__sub {
|
||||
font-size: 1.2rem;
|
||||
color: var(--color-text-muted);
|
||||
max-width: 580px;
|
||||
margin: var(--space-4) 0 var(--space-6);
|
||||
}
|
||||
.hero__sub strong { color: var(--color-text); font-weight: 600; }
|
||||
.hero__cta {
|
||||
display: flex;
|
||||
gap: var(--space-3);
|
||||
flex-wrap: wrap;
|
||||
margin-bottom: var(--space-6);
|
||||
}
|
||||
.hero__proof {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: var(--space-2);
|
||||
}
|
||||
.hero__visual svg {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
max-width: 480px;
|
||||
filter: drop-shadow(0 10px 40px rgba(0, 229, 255, 0.15));
|
||||
}
|
||||
|
||||
/* ---------- Values ---------- */
|
||||
.values-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: var(--space-5);
|
||||
}
|
||||
@media (max-width: 760px) { .values-grid { grid-template-columns: 1fr; } }
|
||||
.value {
|
||||
border-left: 2px solid var(--color-accent);
|
||||
padding: var(--space-2) var(--space-5);
|
||||
}
|
||||
.value h3 { font-size: 1.4rem; margin-bottom: var(--space-2); }
|
||||
.value p { margin: 0; color: var(--color-text-muted); }
|
||||
|
||||
/* ---------- Section heads ---------- */
|
||||
.section-head { margin-bottom: var(--space-6); max-width: 720px; }
|
||||
.section-head h2 { margin-bottom: var(--space-3); }
|
||||
.section-head__lead { font-size: 1.05rem; }
|
||||
|
||||
/* ---------- Proof ---------- */
|
||||
.proof {
|
||||
background: linear-gradient(180deg, transparent, var(--color-bg-soft), transparent);
|
||||
border-top: 1px solid var(--color-border-soft);
|
||||
border-bottom: 1px solid var(--color-border-soft);
|
||||
}
|
||||
.proof__inner {
|
||||
display: grid;
|
||||
grid-template-columns: 1.2fr 1fr;
|
||||
gap: var(--space-7);
|
||||
align-items: center;
|
||||
}
|
||||
@media (max-width: 860px) { .proof__inner { grid-template-columns: 1fr; } }
|
||||
.proof__stats {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: var(--space-4);
|
||||
}
|
||||
.proof__stats > div {
|
||||
background: var(--color-surface);
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-md);
|
||||
padding: var(--space-5) var(--space-4);
|
||||
text-align: center;
|
||||
}
|
||||
.proof__stats strong {
|
||||
display: block;
|
||||
font-size: 2rem;
|
||||
color: var(--color-accent);
|
||||
font-family: var(--font-mono);
|
||||
margin-bottom: var(--space-1);
|
||||
}
|
||||
.proof__stats span { color: var(--color-text-dim); font-size: 0.85rem; }
|
||||
|
||||
/* ---------- Blog tease ---------- */
|
||||
.post-card {
|
||||
background: linear-gradient(180deg, var(--color-surface), var(--color-surface-2));
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: var(--space-5);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-3);
|
||||
color: var(--color-text);
|
||||
transition: border-color var(--transition), transform var(--transition);
|
||||
}
|
||||
.post-card:hover {
|
||||
border-color: rgba(0, 229, 255, 0.4);
|
||||
transform: translateY(-3px);
|
||||
color: var(--color-text);
|
||||
}
|
||||
.post-card h3 { margin: 0; font-size: 1.2rem; }
|
||||
.post-card p { margin: 0; flex: 1; }
|
||||
|
||||
/* ---------- Final CTA ---------- */
|
||||
.cta {
|
||||
text-align: center;
|
||||
background:
|
||||
radial-gradient(600px 240px at 50% 50%, rgba(0, 229, 255, 0.12), transparent 70%);
|
||||
}
|
||||
.cta__inner { max-width: 640px; margin: 0 auto; }
|
||||
.cta h2 { margin-bottom: var(--space-3); }
|
||||
.cta p { margin-bottom: var(--space-5); }
|
||||
</style>
|
||||
25
frontend/src/views/NotFoundView.vue
Normal file
25
frontend/src/views/NotFoundView.vue
Normal file
@@ -0,0 +1,25 @@
|
||||
<script setup>
|
||||
import { RouterLink } from 'vue-router'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="section nf">
|
||||
<div class="container nf__inner">
|
||||
<span class="mono dim">ERR · 404</span>
|
||||
<h1>Lost in orbit.</h1>
|
||||
<p class="muted">The page you're looking for has drifted. Let's get you back.</p>
|
||||
<div class="nf__cta">
|
||||
<RouterLink to="/" class="btn btn--primary">Home</RouterLink>
|
||||
<RouterLink to="/products" class="btn btn--ghost">Products</RouterLink>
|
||||
<RouterLink to="/contact" class="btn btn--ghost">Talk to us</RouterLink>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.nf { min-height: 60vh; display: flex; align-items: center; }
|
||||
.nf__inner { text-align: center; max-width: 560px; margin: 0 auto; }
|
||||
.nf h1 { margin-top: var(--space-3); font-size: clamp(2.5rem, 7vw, 4.5rem); }
|
||||
.nf__cta { display: flex; gap: var(--space-3); justify-content: center; flex-wrap: wrap; margin-top: var(--space-5); }
|
||||
</style>
|
||||
231
frontend/src/views/ProductDetailView.vue
Normal file
231
frontend/src/views/ProductDetailView.vue
Normal file
@@ -0,0 +1,231 @@
|
||||
<script setup>
|
||||
import { computed, onMounted, ref, watch } from 'vue'
|
||||
import { useRoute, RouterLink } from 'vue-router'
|
||||
import { api } from '@/api/client'
|
||||
|
||||
const route = useRoute()
|
||||
const product = ref(null)
|
||||
const loading = ref(true)
|
||||
const notFound = ref(false)
|
||||
|
||||
async function load(slug) {
|
||||
loading.value = true
|
||||
notFound.value = false
|
||||
try {
|
||||
product.value = await api.getProduct(slug)
|
||||
if (product.value?.name) document.title = `${product.value.name} — RisingCompute`
|
||||
} catch (e) {
|
||||
notFound.value = true
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => load(route.params.slug))
|
||||
watch(() => route.params.slug, (s) => s && load(s))
|
||||
|
||||
const interestMap = {
|
||||
ai: 'ai-ip',
|
||||
security: 'security-ip',
|
||||
comms: 'comms-ip',
|
||||
asic: 'custom-asic',
|
||||
}
|
||||
const contactInterest = computed(() => interestMap[product.value?.category] || 'other')
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-if="loading" class="container section dim mono">Loading…</div>
|
||||
|
||||
<section v-else-if="notFound" class="section text-center">
|
||||
<div class="container">
|
||||
<h1>Product not found.</h1>
|
||||
<p class="muted">It may have moved, or never existed.</p>
|
||||
<RouterLink to="/products" class="btn btn--ghost">Back to products</RouterLink>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<template v-else>
|
||||
<!-- HERO -->
|
||||
<section class="product-hero">
|
||||
<div class="container">
|
||||
<RouterLink to="/products" class="back-link">← All products</RouterLink>
|
||||
<span class="pill">{{ product.category_label }}</span>
|
||||
<h1>{{ product.name }}</h1>
|
||||
<p class="product-hero__tagline">{{ product.tagline }}</p>
|
||||
<div class="product-hero__cta">
|
||||
<RouterLink :to="{ path: '/contact', query: { interest: contactInterest } }" class="btn btn--primary">
|
||||
{{ product.primary_cta_label }}
|
||||
</RouterLink>
|
||||
<RouterLink to="/contact" class="btn btn--ghost">Request datasheet →</RouterLink>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- OVERVIEW + BENEFITS -->
|
||||
<section class="section">
|
||||
<div class="container product-grid">
|
||||
<div class="product-grid__copy">
|
||||
<span class="eyebrow">Overview</span>
|
||||
<p class="product-grid__lead">{{ product.summary }}</p>
|
||||
<p>{{ product.description }}</p>
|
||||
</div>
|
||||
|
||||
<aside class="product-grid__side">
|
||||
<h3 class="aside-h">Benefits</h3>
|
||||
<ul class="check-list">
|
||||
<li v-for="b in product.benefits" :key="b">
|
||||
<span class="check">✓</span><span>{{ b }}</span>
|
||||
</li>
|
||||
</ul>
|
||||
</aside>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- FEATURES -->
|
||||
<section class="section section--tight features-section" v-if="product.features?.length">
|
||||
<div class="container">
|
||||
<span class="eyebrow">What's included</span>
|
||||
<h2>Features</h2>
|
||||
<div class="grid grid--3 features">
|
||||
<div v-for="f in product.features" :key="f" class="feature">
|
||||
<span class="feature__dot mono">+</span>
|
||||
<p>{{ f }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- SPECS -->
|
||||
<section class="section" v-if="product.spec_table?.length">
|
||||
<div class="container">
|
||||
<span class="eyebrow">Spec sheet</span>
|
||||
<h2>At a glance</h2>
|
||||
<div class="specs">
|
||||
<div v-for="row in product.spec_table" :key="row.label" class="spec-row">
|
||||
<span class="spec-row__label mono">{{ row.label }}</span>
|
||||
<span class="spec-row__value">{{ row.value }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<p class="dim mono spec-note">
|
||||
Full numbers, gate counts, and target-node performance disclosed under NDA.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- CTA -->
|
||||
<section class="section cta">
|
||||
<div class="container cta__inner">
|
||||
<h2>Evaluate {{ product.name }}.</h2>
|
||||
<p class="muted">Get a datasheet, a reference design, and a 30-minute architect call.</p>
|
||||
<RouterLink :to="{ path: '/contact', query: { interest: contactInterest } }" class="btn btn--primary">
|
||||
{{ product.primary_cta_label }}
|
||||
</RouterLink>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.back-link {
|
||||
display: inline-block;
|
||||
color: var(--color-text-dim);
|
||||
font-size: 0.9rem;
|
||||
margin-bottom: var(--space-4);
|
||||
}
|
||||
.back-link:hover { color: var(--color-accent); }
|
||||
|
||||
.product-hero {
|
||||
padding: var(--space-8) 0 var(--space-6);
|
||||
border-bottom: 1px solid var(--color-border-soft);
|
||||
background: radial-gradient(800px 360px at 90% 0%, rgba(0, 229, 255, 0.08), transparent 60%);
|
||||
}
|
||||
.product-hero h1 { margin-top: var(--space-3); }
|
||||
.product-hero__tagline { color: var(--color-accent); font-size: 1.2rem; max-width: 720px; }
|
||||
.product-hero__cta { display: flex; gap: var(--space-3); flex-wrap: wrap; margin-top: var(--space-5); }
|
||||
|
||||
.product-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1.6fr 1fr;
|
||||
gap: var(--space-7);
|
||||
}
|
||||
@media (max-width: 900px) { .product-grid { grid-template-columns: 1fr; } }
|
||||
.product-grid__lead { font-size: 1.15rem; color: var(--color-text); }
|
||||
.product-grid__side {
|
||||
background: linear-gradient(180deg, var(--color-surface), var(--color-surface-2));
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: var(--space-5);
|
||||
position: sticky;
|
||||
top: calc(var(--nav-height) + var(--space-4));
|
||||
}
|
||||
.aside-h {
|
||||
font-size: 0.8rem;
|
||||
letter-spacing: 0.1em;
|
||||
text-transform: uppercase;
|
||||
color: var(--color-text-dim);
|
||||
margin-bottom: var(--space-3);
|
||||
}
|
||||
.check-list {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
display: grid;
|
||||
gap: var(--space-3);
|
||||
}
|
||||
.check-list li {
|
||||
display: flex;
|
||||
gap: var(--space-3);
|
||||
align-items: flex-start;
|
||||
color: var(--color-text-muted);
|
||||
}
|
||||
.check {
|
||||
color: var(--color-accent);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.features-section { background: linear-gradient(180deg, transparent, var(--color-bg-soft), transparent); border-block: 1px solid var(--color-border-soft); }
|
||||
.feature {
|
||||
display: flex;
|
||||
gap: var(--space-3);
|
||||
align-items: flex-start;
|
||||
padding: var(--space-3) 0;
|
||||
}
|
||||
.feature__dot {
|
||||
flex: 0 0 28px;
|
||||
width: 28px; height: 28px;
|
||||
border-radius: 50%;
|
||||
background: var(--color-accent-soft);
|
||||
color: var(--color-accent);
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.feature p { margin: 0; color: var(--color-text); }
|
||||
|
||||
.specs {
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-lg);
|
||||
overflow: hidden;
|
||||
background: var(--color-surface);
|
||||
}
|
||||
.spec-row {
|
||||
display: grid;
|
||||
grid-template-columns: 200px 1fr;
|
||||
padding: var(--space-4) var(--space-5);
|
||||
border-top: 1px solid var(--color-border-soft);
|
||||
}
|
||||
.spec-row:first-child { border-top: 0; }
|
||||
.spec-row__label { color: var(--color-text-dim); font-size: 0.85rem; letter-spacing: 0.05em; text-transform: uppercase; }
|
||||
.spec-row__value { color: var(--color-text); }
|
||||
@media (max-width: 640px) {
|
||||
.spec-row { grid-template-columns: 1fr; gap: var(--space-1); }
|
||||
}
|
||||
.spec-note { margin-top: var(--space-3); font-size: 0.78rem; }
|
||||
|
||||
.cta {
|
||||
text-align: center;
|
||||
background: radial-gradient(600px 240px at 50% 50%, rgba(0, 229, 255, 0.1), transparent 70%);
|
||||
}
|
||||
.cta__inner { max-width: 640px; margin: 0 auto; }
|
||||
.cta p { margin-bottom: var(--space-5); }
|
||||
</style>
|
||||
53
frontend/src/views/ProductsView.vue
Normal file
53
frontend/src/views/ProductsView.vue
Normal file
@@ -0,0 +1,53 @@
|
||||
<script setup>
|
||||
import { onMounted, ref } from 'vue'
|
||||
import { RouterLink } from 'vue-router'
|
||||
import { api } from '@/api/client'
|
||||
import SectionHero from '@/components/SectionHero.vue'
|
||||
import ProductCard from '@/components/ProductCard.vue'
|
||||
|
||||
const products = ref([])
|
||||
const loading = ref(true)
|
||||
|
||||
onMounted(async () => {
|
||||
try { products.value = await api.listProducts() }
|
||||
catch (e) {}
|
||||
finally { loading.value = false }
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<SectionHero
|
||||
eyebrow="Products"
|
||||
title="IP cores for AI, space, and robotics."
|
||||
subtitle="Three production-bound blocks. Quote-based licensing. Datasheets and evaluation kits on request."
|
||||
/>
|
||||
|
||||
<section class="section">
|
||||
<div class="container">
|
||||
<div v-if="loading" class="dim mono">Loading…</div>
|
||||
<div v-else class="grid grid--3">
|
||||
<ProductCard v-for="p in products" :key="p.slug" :product="p" />
|
||||
</div>
|
||||
|
||||
<div class="cta-inline">
|
||||
<p class="muted">Looking for a custom block or full ASIC service?</p>
|
||||
<RouterLink to="/contact" class="btn btn--ghost">Start a conversation →</RouterLink>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.cta-inline {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: var(--space-4);
|
||||
margin-top: var(--space-7);
|
||||
padding: var(--space-5);
|
||||
border: 1px dashed var(--color-border);
|
||||
border-radius: var(--radius-lg);
|
||||
}
|
||||
@media (max-width: 640px) { .cta-inline { flex-direction: column; align-items: flex-start; } }
|
||||
.cta-inline p { margin: 0; }
|
||||
</style>
|
||||
156
frontend/src/views/TechnologyView.vue
Normal file
156
frontend/src/views/TechnologyView.vue
Normal file
@@ -0,0 +1,156 @@
|
||||
<script setup>
|
||||
import { RouterLink } from 'vue-router'
|
||||
import SectionHero from '@/components/SectionHero.vue'
|
||||
|
||||
const pillars = [
|
||||
{
|
||||
title: 'Parallel by design',
|
||||
body: 'Datapaths are parallel from the first line of RTL. The architecture is not a serial CPU that we widened — it is parallel-native.',
|
||||
},
|
||||
{
|
||||
title: 'Verification-first',
|
||||
body: 'Every block ships with UVM testbenches, a coverage plan, and traceable test vectors. Heritage you can audit, not heritage you have to take on faith.',
|
||||
},
|
||||
{
|
||||
title: 'FPGA → ASIC portability',
|
||||
body: 'The same RTL synthesises on Xilinx UltraScale+, Intel Agilex, and standard 28nm / 40nm ASIC libraries. Prototype fast, ship slow, but with the same code.',
|
||||
},
|
||||
{
|
||||
title: 'Security as architecture',
|
||||
body: 'Constant-time datapaths, side-channel-aware routing, and a security white paper per release — not a checklist bolted on at integration time.',
|
||||
},
|
||||
]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<SectionHero
|
||||
eyebrow="Technology"
|
||||
title="An architecture built for AI, space, and robotics — in that order."
|
||||
subtitle="A short tour of the design principles that show up in every block we ship. If you want the spec-sheet version, request a datasheet."
|
||||
/>
|
||||
|
||||
<!-- PILLARS -->
|
||||
<section class="section">
|
||||
<div class="container">
|
||||
<div class="grid grid--2 pillars">
|
||||
<article v-for="(p, i) in pillars" :key="p.title" class="pillar">
|
||||
<span class="pillar__num mono">{{ String(i + 1).padStart(2, '0') }}</span>
|
||||
<h3>{{ p.title }}</h3>
|
||||
<p class="muted">{{ p.body }}</p>
|
||||
</article>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- DIAGRAM -->
|
||||
<section class="section diagram-section">
|
||||
<div class="container">
|
||||
<div class="section-head">
|
||||
<span class="eyebrow">System view</span>
|
||||
<h2>The stack, at a glance.</h2>
|
||||
<p class="muted">Three product blocks. One shared verification toolchain. Same RTL from FPGA to ASIC.</p>
|
||||
</div>
|
||||
|
||||
<div class="stack-diagram">
|
||||
<div class="layer layer--top">
|
||||
<span class="layer__title">Customer SoC / FPGA</span>
|
||||
<span class="layer__sub mono">Your design</span>
|
||||
</div>
|
||||
<div class="layer__pipe"></div>
|
||||
<div class="layer-row">
|
||||
<div class="layer layer--block">
|
||||
<span class="layer__title">AI Inference IP</span>
|
||||
<span class="layer__sub mono">INT8 / INT4</span>
|
||||
</div>
|
||||
<div class="layer layer--block">
|
||||
<span class="layer__title">Cybersecurity IP</span>
|
||||
<span class="layer__sub mono">AES · SHA · ECC</span>
|
||||
</div>
|
||||
<div class="layer layer--block">
|
||||
<span class="layer__title">Communication IP</span>
|
||||
<span class="layer__sub mono">SpaceWire · CAN · UART</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layer__pipe"></div>
|
||||
<div class="layer layer--base">
|
||||
<span class="layer__title">Verification & Integration Toolchain</span>
|
||||
<span class="layer__sub mono">UVM · Reference designs · Integration guides</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- CTA -->
|
||||
<section class="section text-center">
|
||||
<div class="container">
|
||||
<h2>Want the long version?</h2>
|
||||
<p class="muted">Request a technical brief or schedule a 30-minute architect call.</p>
|
||||
<RouterLink to="/contact" class="btn btn--primary">Request the brief</RouterLink>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.pillars { gap: var(--space-5); }
|
||||
.pillar {
|
||||
background: linear-gradient(180deg, var(--color-surface), var(--color-surface-2));
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: var(--space-6);
|
||||
position: relative;
|
||||
}
|
||||
.pillar__num {
|
||||
color: var(--color-accent);
|
||||
font-size: 0.8rem;
|
||||
letter-spacing: 0.1em;
|
||||
display: block;
|
||||
margin-bottom: var(--space-3);
|
||||
}
|
||||
|
||||
.diagram-section {
|
||||
background: linear-gradient(180deg, transparent, var(--color-bg-soft), transparent);
|
||||
border-block: 1px solid var(--color-border-soft);
|
||||
}
|
||||
.section-head { margin-bottom: var(--space-6); max-width: 720px; }
|
||||
|
||||
.stack-diagram {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
gap: var(--space-2);
|
||||
max-width: 880px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.layer {
|
||||
background: var(--color-surface);
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-md);
|
||||
padding: var(--space-4) var(--space-5);
|
||||
text-align: center;
|
||||
}
|
||||
.layer--top {
|
||||
background: linear-gradient(180deg, rgba(0, 229, 255, 0.08), var(--color-surface));
|
||||
border-color: rgba(0, 229, 255, 0.3);
|
||||
}
|
||||
.layer--base {
|
||||
background: linear-gradient(0deg, rgba(0, 229, 255, 0.06), var(--color-surface));
|
||||
border-color: rgba(0, 229, 255, 0.25);
|
||||
}
|
||||
.layer__title { display: block; font-weight: 600; font-size: 1.05rem; color: var(--color-text); }
|
||||
.layer__sub { display: block; color: var(--color-text-dim); font-size: 0.8rem; margin-top: var(--space-1); letter-spacing: 0.05em; }
|
||||
.layer__pipe {
|
||||
width: 2px;
|
||||
height: 20px;
|
||||
background: var(--color-accent);
|
||||
align-self: center;
|
||||
opacity: 0.7;
|
||||
}
|
||||
.layer-row {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: var(--space-3);
|
||||
}
|
||||
@media (max-width: 720px) {
|
||||
.layer-row { grid-template-columns: 1fr; }
|
||||
}
|
||||
</style>
|
||||
29
frontend/vite.config.js
Normal file
29
frontend/vite.config.js
Normal file
@@ -0,0 +1,29 @@
|
||||
import { defineConfig, loadEnv } from 'vite'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
import { fileURLToPath, URL } from 'node:url'
|
||||
|
||||
export default defineConfig(({ mode }) => {
|
||||
const env = loadEnv(mode, process.cwd(), '')
|
||||
return {
|
||||
plugins: [vue()],
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': fileURLToPath(new URL('./src', import.meta.url)),
|
||||
},
|
||||
},
|
||||
server: {
|
||||
port: 5173,
|
||||
proxy: {
|
||||
'/api': {
|
||||
target: env.VITE_API_PROXY || 'http://127.0.0.1:8000',
|
||||
changeOrigin: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
build: {
|
||||
outDir: 'dist',
|
||||
sourcemap: false,
|
||||
target: 'es2020',
|
||||
},
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user