Skip to content

Conversation

@jjspace
Copy link
Contributor

@jjspace jjspace commented May 22, 2025

Description

Major changes/focus for this PR:

  • All sandcastle JS code is now treated as a single JS module that should import Cesium and Sandcastle directly
    • if the import statements are not in the sandcastle code they will be added before loaded into the bucket. AFAICT this should account for all existing sandcastles that relied on the global objects
    • This also means these objects are not in global window scope anymore
    • Most of the "boilerplate" that previously existed was to set up the window.startup function specifically to account for modules loading out of order. Switching to type=module eliminates that
    • The types importing for Monaco was updated so that it should support intellisense for Cesium and Sandcastle regardless of the imports
  • New structure for the gallery which splits the code into dedicated files and relies on a new "metadata sidecar yaml" file for info about a sandcastle
    • index.html is the html/css code for a sandcastle, main.js is the JS code for a sandcastle, sandcastle.yaml holds the metadata and is what dictates that a subfolder is even a gallery example in the first place
    • Note that index.html does not contain the full page structure with head and body tags. This means you can no longer load gallery items directly with a path like localhost:8080/Apps/Sandcastle/gallery/3D Models.html.
      • we feel this was not utilized much and restricted the format too much, maybe we can revisit a way to load them outside of the full SC app in the future
    • a new script called buildGallery.js has been created to parse through the new gallery structure and generate a top level list.json file. This also does a little basic validation. Where this script lives and exactly what it does is still a little up in the air

TODO:

  • Clean up the gallery build script if we're satisfied with the organization structure
    • create a "conversion script" to transform all our existing gallery examples Mostly done, will be separate PR
  • Fix loading from a url id
    • Completed in Solidify new Sandcastle React structure #12639
    • Currently the app does not work in a very "react style" and uses a lot of imperative code which is massively conflicting with load order. This is my next focus as a dedicated restructuring pass. after that I think loading will be a lot easier to implement
  • Decide on gallery location
    • Right now it's top level of the sandcastle package, I think that's fine for now.
    • I think the gallery could live outside of the sandcastle project if we wanted. Given recent comments around the desire to be able to point at any gallery directory I built the logic to hopefully be able to point to any directory from the client. More thought still required but it's in my mind.

Issue number and link

Part of #12566

Testing plan

  • run node buildGallery.js to generate the list file
    • need to figure out how to incorporate this into the build nicer
  • Load sandcastle both with npm run dev and from the normal server npm start after npm run build
  • Make sure the gallery still loads and clicking them loads the examples
    • may want to consider better where these files live for access from both locations and when deployed
  • Make sure types in monaco still show up, with and without the import statements
  • Copy in the sandcastle code from another sandcastle and make sure it still works

Author checklist

  • I have submitted a Contributor License Agreement
  • I have added my name to CONTRIBUTORS.md
  • I have updated CHANGES.md with a short summary of my change
  • I have added or updated unit tests to ensure consistent code coverage
  • I have updated the inline documentation, and included code examples where relevant
  • I have performed a self-review of my code

@jjspace jjspace requested a review from ggetz May 22, 2025 18:07
@github-actions
Copy link

Thank you for the pull request, @jjspace!

✅ We can confirm we have a CLA on file for you.

@jjspace
Copy link
Contributor Author

jjspace commented May 22, 2025

@ggetz I tried to split the commits a little between the new gallery files and actual code changes if that makes it easier to review

@jjspace
Copy link
Contributor Author

jjspace commented May 22, 2025

@ggetz I know there's still some scattered commented code and console logs. I'll do a cleanup pass on those before this gets merged but wanted to just validate the approach first.

</script>
<!-- <script type="module" src="./Sandcastle.js"></script> -->
<script src="__CESIUM_BASE_URL__/Cesium.js" vite-ignore></script>
<script type="module">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to set window.CESIUM_BASE_URL here as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It still needs to be set somewhere and in a file that's processed by Vite to get the correct path based on the env it's building for. I think this is still the best way to do that. Let me know if you have a better idea.

if (host.includes("localhost")) {
document.title = `${host.replace("localhost:", "")} ${document.title}`;
} else if (host.includes("ci")) {
document.title = `CI ${document.title}`;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the goal here? "CI" is an implementation detail for many who just want to view a demo.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was a bit of a quick patch mainly to help me while developing so I can tell which "environment" each tab I have open is in. This will probably get cleaned up more and include the actual title of a sandcastle for gallery items. I don't think "CI" is that bad here since it's very likely to only be running and deployed in our own CI. This wouldn't impact an actual "prod" version

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think even in cases where something is deployed to branch, there's still cases where the Sandcastle is used for demo purposed. For instance, the recent Gaussian Splats work is being shown in example Sandcastles from that branch.

@jjspace
Copy link
Contributor Author

jjspace commented Jun 5, 2025

Reminder for myself, I realized the gallery is not working in CI. I think this is just a matter of not running the build gallery script in CI and boy updating the gallery url. I think this should be a quick fix but I'll take a look tomorrow

@jjspace
Copy link
Contributor Author

jjspace commented Jun 6, 2025

@ggetz I've updated this PR to address most of your comments and responded to others. I think there's still a bit of cleanup I have yet to do but hopefully this is closer.

The gallery has been solidified a bit and the route is now changed depending on the environment so the CI build now has a working gallery again. It also no longer gets copied and duplicated into the local build, instead it points to the packages/sandcastle/gallery directory so local edits will always be reflected immediately.

Comment on lines +375 to +376
// TODO: there's probably a race condition here where the list might not be loaded yet
// I need to switch this to the more React declarative style
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This part is already addressed in #12639

@javagl
Copy link
Contributor

javagl commented Jun 11, 2025

The buildSandcastles.js causes some hiccups on Windows.

  • import.meta.url is file:///C:/cesium/packages/sandcastle/scripts/buildGallery.js
  • process.argv[1] is C:\cesium\packages\sandcastle\scripts\buildGallery.js

causing it to not even enter buildGalleryList. When "fixing" that pragmatically, sindresorhus/globby#155 kicks in. Investigating some options...

EDIT:

I think that

import { pathToFileURL } from "node:url";

...

if (import.meta.url.endsWith(pathToFileURL(process.argv[1]))) {
  const defaultGalleryDirectory = "../gallery";
  const { output, hasErrors } = buildGalleryList(defaultGalleryDirectory);
  console.log("processed", output.entries.length, "sandcastles");
  if (hasErrors) {
    exit(1);
  }
}

might work, if that's OK on other OSes.

@jjspace
Copy link
Contributor Author

jjspace commented Jun 11, 2025

Good catch, sorry about that @javagl. That little bit of code is something I've used in another project based on this answer for how to detect if an es module is "main" but I've only ever used it on linux.

Your suggested solution seems to still work fine so I pushed that up as a fix. Longer term if we integrate the build function with builds correctly we may not even need to keep that "is main" detection at all, but it's been helpful while building that script so I left it for now 🤷‍♀️

@javagl
Copy link
Contributor

javagl commented Jun 11, 2025

Beyond the comment above, I'm not in the position to do a profound technical review (regarding vite, tsx, or CI details).

Details that may already be on the radar:

  • It's necessary to run npm run buld-app in the package/sandcastle directory (that may be evident, or OBE when this is merged, and maybe the documentation is or will be updated, but I just ran the usual npm run start and was surprised that I could open the Sandcastle, but not the Sandcastle2)
  • It's necessary to explicitly run npm run build-ts (because the code completion needs the TS part, apparently)

Some comments that may not belong here, but of which I don't know where they belong (maybe #12639 ?)

  • The new "Add... " buttons are really useful.
    • One thing that I'm a big fan of, and that I've always been missing in the old sandcastle, are sliders. Dragging and seeing the change just makes me feel so connected to my little computing machine 🤗 . It would be great if that could go on the medium-term radar. like Sandcastle.addSlider("Slide!", min, max, value, function(currentValue) {...}).
    • The "Add..." buttons are inserting at the bottom of the code. Could they insert at the current cursor position?
  • I tried the basic parts of code completion, and I'm a big fan of that as well
    • Pressing key sequences like "A [CTRL+Space] . S [ DOWN, ENTER ] ( n [CTRL+Space] [ENTER] )" to write a line like applicationWindow.showInputDialog(nameProvider) just feels so more efficient than "real typing"...
    • The help only appears when one of the dropdown options is selected. This is the same as for VSCode. I'm probably just spoiled...
  • The fact that the HTML panel is always visible below the code panel might be hard to get used to...
  • The window elements are all fixed size. I assume/hope that they will (all) become such "draggable splitters" like in the old sandcastle

Some comments that may belong here:

I have a bunch of Sandcastles from Forum support. They are just a bunch of .js files in a directory. (And sometimes HTML, when I needed a slider 😆 ). They follow the name pattern
Sandcastle Forum <threadId> <short summary>.js
And I wrote a short script that just squeezes them into the required gallery structure: Create directories called short-summary, copy the .js file there as main.js, add some dummy thumbnail and index.html, and a sandcastle.yaml. And the running dev server immediately picked them up:

Cesium SandcastleV2 0001

Yeah, the thumbnail layout is not perfect (and there is no horizontal scrollbar), but the technical structure seems to work nicely.

It's not yet clear how exactly the old sandcastles will be "migrated" into the new structure. But given that the target structure is relatively simple (with clearly separated files, and each directory being "one sandcastle"), this shouldn't be too hard.

@ggetz
Copy link
Contributor

ggetz commented Jun 12, 2025

@jjspace I'm taking another pass now, thank you for the updates! It'd be super helpful for me if you go back to your original comment and update description and your TODO list. It helps me understand the status. Are you still working through items in this PR, or is everything ready for final review before merge?

@jjspace
Copy link
Contributor Author

jjspace commented Jun 12, 2025

I started working on the conversion script (pretty quick and working well) but I realized we forgot to think about the development only sandcastles

How should we handle the development sandcastles? Still a separate directory? should it be nested? or should it just be a new label? or maybe a property of the yaml?

I think there's 2 options I like

  1. Add a new property to the sandcastle.yaml metadata for developmentOnly which is optional and defaults to false.
    • Then we can modify the list generation to ignore any where it's true for prod
  2. A separate directory alongside the new gallery directory, not nested
    • if it was nested that's adding annoying special handling to treat it differently than the other sub-directories
    • If we do this we'd have to generate a second gallery-list
    • This is potentially easier to manage from a maintainer perspective as it's more clear if a sandcastle is development only or not depending where it's located. Similar to how it is now.

Adjacent question, does it make sense to support loading multiple galleries? probably not tooo difficult but not sure if it's worth

This is most important if we go with option 2 above so we could load just the main gallery or the main gallery and the development gallery.
This could also enable us to let developers point to their own gallery in addition to the default gallery. However I don't think that would really apply to anyone other than maybe @javagl right now

@ggetz thoughts?

};

// Convert the viewModel members into knockout observables.
Cesium.knockout.track(viewModel);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Totally out of scope of this PR, but we should really make a pass at getting rid of knockout from our examples. It leads to users depending on it, and ideally we want to move away from depending on it. Could you please write up an issue to take a content pass to get rid of the knockout bindings from Sandcastle examples?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think most of the places it's used in sandcastles right now are to set up sliders and more complex toolbar inputs. I was thinking this could be handled by expanding the Sandcastle "API" with more features. It's been in the back of my mind but I'll make sure it's written up somewhere

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good. I think it'll be good to write up an issue just in case we don't cover all the cases. If we end up doing so, then 🎉, we can close that issue.

@ggetz
Copy link
Contributor

ggetz commented Jun 12, 2025

How should we handle the development sandcastles? Still a separate directory? should it be nested? or should it just be a new label? or maybe a property of the yaml?

Making it a property of the yaml file seems easier to manage from a content generation perspective IMO. Though I may suggest using development as the property for brevity. 🙂

Ultimately though, either approach should be fine as long as there is one standard process and it is documented.

@ggetz
Copy link
Contributor

ggetz commented Jun 12, 2025

Adjacent question, does it make sense to support loading multiple galleries? probably not tooo difficult but not sure if it's worth

Worth discussing, but could we park the implementation this for now and address it in a later PR?

};

// Convert the viewModel members into knockout observables.
Cesium.knockout.track(viewModel);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good. I think it'll be good to write up an issue just in case we don't cover all the cases. If we end up doing so, then 🎉, we can close that issue.

{
"include": ["./Sandcastle.ts"],
"compilerOptions": {
"tsBuildInfoFile": "../node_modules/.tmp/tsconfig.lib.tsbuildinfo",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So why do we need to set tsBuildInfoFile? And why is it using a path in node_modules?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Without setting it it defaults to output this file in the same directory. I set it to inside the node modules just matching the pattern in the main tsconfig that was generated from the vite setup. the node_modules is already gitignored so it seems like a reasonable place to put some of these extra build related temp files.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's generally discouraged to write or modify any content to the node_modules folder, as it is inherently transitory. Please use another location and add it to the .gitignore as necessary.

What's the issue that arises when that file is written to the current directory? By default, this is written to next to the "out" location, so it may make sense to adjust the output location instead.

Copy link
Contributor Author

@jjspace jjspace Jun 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's generally discouraged to write or modify any content to the node_modules folder, as it is inherently transitory.

Generally I would agree with you. However this is following the example set by the default tsconfig set up with the vite template. As I understand it the tsbuildinfo file is also pretty temporary and only there to help speed up subsequent local builds.

What's the issue that arises when that file is written to the current directory?

Just extra noise in the file tree and needing to add it specifically to the gitignore.

Edit:
Looks like their motivation was the same as mine. It's just a nice easy place to put these temp files that's already under the gitignore umbrella with the rest of node_modules vitejs/vite#18435

If you still think they should be moved elsewhere just lmk where. I don't want to bikeshed on this

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But this is not built using vite, correct? It's built with tsc.

What vite does internally isn't so much my concern– But making sure our project follows good practices and is maintainable is. I'm concerned this approach is obscuring details by doing things in a non-conventional way, making things more difficult to understand and maintain for others in the future.

Sandcastle.js and Sandcastle.d.ts are already ignored correct? Perhaps the cleanest solution would be to set the output to a subdirectory, such as templates/dist and ignore the entire directory in the .gitignore.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But this is not built using vite, correct? It's built with tsc.

It is built with vite when running the local dev server to allow for quicker updates when actively developing sandcastle directly.

What vite does internally isn't so much my concern– But making sure our project follows good practices and is maintainable is. I'm concerned this approach is obscuring details by doing things in a non-conventional way, making things more difficult to understand and maintain for others in the future.

The point I was trying to make is that the method I was using (tmp dir in node_modules) is what the vite scaffold project does by default. I extrapolated this to mean that that is the conventional or expected way to handle these files and is a "good practice". At least the expected way within vite projects.

Regardless, I've moved them all next to their configs by just removing the config path. It's easy to change later if we want

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for updating. We can circle back to this discussion and to vite practices as needed, but I think what's there now is just easier to understand at the end of the day.

@ggetz
Copy link
Contributor

ggetz commented Jun 12, 2025

I'm still attempting to test this out, by npm appears to have other plans...

image

@ggetz
Copy link
Contributor

ggetz commented Jun 13, 2025

@jjspace Ok to handle this in a follow up PR, just let me know the plan.

I noticed two things about "New" sandcastles:

  • Should a new Sandcastle now be the following?
import * as Cesium from "cesium";

const viewer = new Cesium.Viewer("cesiumContainer");
  • I noticed the autocomplete suggestions were working for loaded gallery examples, but not for "New" sandcastles.

@ggetz
Copy link
Contributor

ggetz commented Jun 13, 2025

Otherwise, I tested this out by running the following commands and things appear to be running smoothly.

npm run build
npm run build-sandcastle
npm start

@jjspace
Copy link
Contributor Author

jjspace commented Jun 13, 2025

Should a new Sandcastle now be the following?

It's not required but I'm fine encouraging it to follow closer to how people would use in their own applications.

I noticed the autocomplete suggestions were working for loaded gallery examples, but not for "New" sandcastles.

They should work for both scenarios. Can you make sure the declaration file is generated for Sandcastle using npx tsc -b? It's possible the network request is failing and then not setting up the types for intellisense.
If that's not the cause can you be more specific how to reproduce?

@ggetz
Copy link
Contributor

ggetz commented Jun 13, 2025

From the repo root:

npm clean -dxf
npm install
npm run build
npm run build-sandcastle
npm start
  1. The first time I open Sandcastle, see the following message. (That wasn't happening before your last commit I believe).
image
  1. If I switch to a gallery example, everything works fine.

  2. If I press the "New" button, the console looks cleaner, but I still don't see suggestions for Cesium.

image image

Sandcastle suggestions look to be working fine though.

image

@jjspace
Copy link
Contributor Author

jjspace commented Jun 16, 2025

@ggetz Updated, please take another look. I think it should be good to go

@ggetz
Copy link
Contributor

ggetz commented Jun 27, 2025

Thanks @jjspace, especially for your patience! 😬

@ggetz ggetz merged commit 6e3a872 into sandcastle-v2 Jun 27, 2025
9 checks passed
@ggetz ggetz deleted the nested-gallery branch June 27, 2025 19:38
@jjspace jjspace mentioned this pull request Sep 2, 2025
6 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants